File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_msfees.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /* refclock_ees - clock driver for the EES M201 receiver */
    2: 
    3: #ifdef HAVE_CONFIG_H
    4: #include <config.h>
    5: #endif
    6: 
    7: #if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS)
    8: 
    9: /* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
   10:  * were removed as the code was overly hairy, they weren't in use
   11:  * (hence probably didn't work).  Still in RCS file at cl.cam.ac.uk
   12:  */
   13: 
   14: #include "ntpd.h"
   15: #include "ntp_io.h"
   16: #include "ntp_refclock.h"
   17: #include "ntp_unixtime.h"
   18: #include "ntp_calendar.h"
   19: 
   20: #include <ctype.h>
   21: #if defined(HAVE_BSD_TTYS)
   22: #include <sgtty.h>
   23: #endif /* HAVE_BSD_TTYS */
   24: #if defined(HAVE_SYSV_TTYS)
   25: #include <termio.h>
   26: #endif /* HAVE_SYSV_TTYS */
   27: #if defined(HAVE_TERMIOS)
   28: #include <termios.h>
   29: #endif
   30: #if defined(STREAM)
   31: #include <stropts.h>
   32: #endif
   33: 
   34: #ifdef HAVE_SYS_TERMIOS_H
   35: # include <sys/termios.h>
   36: #endif
   37: #ifdef HAVE_SYS_PPSCLOCK_H
   38: # include <sys/ppsclock.h>
   39: #endif
   40: 
   41: #include "ntp_stdlib.h"
   42: 
   43: int dbg = 0;
   44: /*
   45: 	fudgefactor	= fudgetime1;
   46: 	os_delay	= fudgetime2;
   47: 	   offset_fudge	= os_delay + fudgefactor + inherent_delay;
   48: 	stratumtouse	= fudgeval1 & 0xf
   49: 	dbg		= fudgeval2;
   50: 	sloppyclockflag	= flags & CLK_FLAG1;
   51: 		1	  log smoothing summary when processing sample
   52: 		4	  dump the buffer from the clock
   53: 		8	  EIOGETKD the last n uS time stamps
   54: 	if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
   55: 	ees->dump_vals	= flags & CLK_FLAG3;
   56: 	ees->usealldata	= flags & CLK_FLAG4;
   57: 
   58: 
   59: 	bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
   60: 	bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
   61: 	bug->values[2] = (u_long)ees->status;
   62: 	bug->values[3] = (u_long)ees->lastevent;
   63: 	bug->values[4] = (u_long)ees->reason;
   64: 	bug->values[5] = (u_long)ees->nsamples;
   65: 	bug->values[6] = (u_long)ees->codestate;
   66: 	bug->values[7] = (u_long)ees->day;
   67: 	bug->values[8] = (u_long)ees->hour;
   68: 	bug->values[9] = (u_long)ees->minute;
   69: 	bug->values[10] = (u_long)ees->second;
   70: 	bug->values[11] = (u_long)ees->tz;
   71: 	bug->values[12] = ees->yearstart;
   72: 	bug->values[13] = (ees->leaphold > current_time) ?
   73: 				ees->leaphold - current_time : 0;
   74: 	bug->values[14] = inherent_delay[unit].l_uf;
   75: 	bug->values[15] = offset_fudge[unit].l_uf;
   76: 
   77: 	bug->times[0] = ees->reftime;
   78: 	bug->times[1] = ees->arrvtime;
   79: 	bug->times[2] = ees->lastsampletime;
   80: 	bug->times[3] = ees->offset;
   81: 	bug->times[4] = ees->lowoffset;
   82: 	bug->times[5] = ees->highoffset;
   83: 	bug->times[6] = inherent_delay[unit];
   84: 	bug->times[8] = os_delay[unit];
   85: 	bug->times[7] = fudgefactor[unit];
   86: 	bug->times[9] = offset_fudge[unit];
   87: 	bug->times[10]= ees->yearstart, 0;
   88: 	*/
   89: 
   90: /* This should support the use of an EES M201 receiver with RS232
   91:  * output (modified to transmit time once per second).
   92:  *
   93:  * For the format of the message sent by the clock, see the EESM_
   94:  * definitions below.
   95:  *
   96:  * It appears to run free for an integral number of minutes, until the error
   97:  * reaches 4mS, at which point it steps at second = 01.
   98:  * It appears that sometimes it steps 4mS (say at 7 min interval),
   99:  * then the next minute it decides that it was an error, so steps back.
  100:  * On the next minute it steps forward again :-(
  101:  * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
  102:  * or 9.5uS/S then 3990.5uS at a 7min re-sync,
  103:  * at which point it may lose the "00" second time stamp.
  104:  * I assume that the most accurate time is just AFTER the re-sync.
  105:  * Hence remember the last cycle interval,
  106:  *
  107:  * Can run in any one of:
  108:  *
  109:  *	PPSCD	PPS signal sets CD which interupts, and grabs the current TOD
  110:  *	(sun)		*in the interupt code*, so as to avoid problems with
  111:  *			the STREAMS scheduling.
  112:  *
  113:  * It appears that it goes 16.5 uS slow each second, then every 4 mins it
  114:  * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
  115:  */
  116: 
  117: /* Definitions */
  118: #ifndef	MAXUNITS
  119: #define	MAXUNITS	4	/* maximum number of EES units permitted */
  120: #endif
  121: 
  122: #ifndef	EES232
  123: #define	EES232	"/dev/ees%d"	/* Device to open to read the data */
  124: #endif
  125: 
  126: /* Other constant stuff */
  127: #ifndef	EESPRECISION
  128: #define	EESPRECISION	(-10)		/* what the heck - 2**-10 = 1ms */
  129: #endif
  130: #ifndef	EESREFID
  131: #define	EESREFID	"MSF\0"		/* String to identify the clock */
  132: #endif
  133: #ifndef	EESHSREFID
  134: #define	EESHSREFID	(0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
  135: #endif
  136: 
  137: /* Description of clock */
  138: #define	EESDESCRIPTION		"EES M201 MSF Receiver"
  139: 
  140: /* Speed we run the clock port at. If this is changed the UARTDELAY
  141:  * value should be recomputed to suit.
  142:  */
  143: #ifndef	SPEED232
  144: #define	SPEED232	B9600	/* 9600 baud */
  145: #endif
  146: 
  147: /* What is the inherent delay for this mode of working, i.e. when is the
  148:  * data time stamped.
  149:  */
  150: #define	SAFETY_SHIFT	10	/* Split the shift to avoid overflow */
  151: #define	BITS_TO_L_FP(bits, baud) \
  152: (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
  153: #define	INH_DELAY_CBREAK	BITS_TO_L_FP(119, 9600)
  154: #define	INH_DELAY_PPS		BITS_TO_L_FP(  0, 9600)
  155: 
  156: #ifndef	STREAM_PP1
  157: #define	STREAM_PP1	"ppsclocd\0<-- patch space for module name1 -->"
  158: #endif
  159: #ifndef	STREAM_PP2
  160: #define	STREAM_PP2	"ppsclock\0<-- patch space for module name2 -->"
  161: #endif
  162: 
  163:      /* Offsets of the bytes of the serial line code.  The clock gives
  164:  * local time with a GMT/BST indication. The EESM_ definitions
  165:  * give offsets into ees->lastcode.
  166:  */
  167: #define EESM_CSEC	 0	/* centiseconds - always zero in our clock  */
  168: #define EESM_SEC	 1	/* seconds in BCD			    */
  169: #define EESM_MIN	 2	/* minutes in BCD			    */
  170: #define EESM_HOUR	 3	/* hours in BCD				    */
  171: #define EESM_DAYWK	 4	/* day of week (Sun = 0 etc)		    */
  172: #define EESM_DAY	 5	/* day of month in BCD			    */
  173: #define EESM_MON	 6	/* month in BCD				    */
  174: #define EESM_YEAR	 7	/* year MOD 100 in BCD			    */
  175: #define EESM_LEAP	 8	/* 0x0f if leap year, otherwise zero        */
  176: #define EESM_BST	 9	/* 0x03 if BST, 0x00 if GMT		    */
  177: #define EESM_MSFOK	10	/* 0x3f if radio good, otherwise zero	    */
  178: 				/* followed by a frame alignment byte (0xff) /
  179: 				/  which is not put into the lastcode buffer*/
  180: 
  181: /* Length of the serial time code, in characters.  The first length
  182:  * is less the frame alignment byte.
  183:  */
  184: #define	LENEESPRT	(EESM_MSFOK+1)
  185: #define	LENEESCODE	(LENEESPRT+1)
  186: 
  187:      /* Code state. */
  188: #define	EESCS_WAIT	0       /* waiting for start of timecode */
  189: #define	EESCS_GOTSOME	1	/* have an incomplete time code buffered */
  190: 
  191:      /* Default fudge factor and character to receive */
  192: #define	DEFFUDGETIME	0	/* Default user supplied fudge factor */
  193: #ifndef	DEFOSTIME
  194: #define	DEFOSTIME	0	/* Default OS delay -- passed by Make ? */
  195: #endif
  196: #define	DEFINHTIME	INH_DELAY_PPS /* inherent delay due to sample point*/
  197: 
  198:      /* Limits on things.  Reduce the number of samples to SAMPLEREDUCE by median
  199:  * elimination.  If we're running with an accurate clock, chose the BESTSAMPLE
  200:  * as the estimated offset, otherwise average the remainder.
  201:  */
  202: #define	FULLSHIFT	6			/* NCODES root 2 */
  203: #define NCODES		(1<< FULLSHIFT)		/* 64 */
  204: #define	REDUCESHIFT	(FULLSHIFT -1)		/* SAMPLEREDUCE root 2 */
  205: 
  206:      /* Towards the high ( Why ?) end of half */
  207: #define	BESTSAMPLE	((samplereduce * 3) /4)	/* 24 */
  208: 
  209:      /* Leap hold time.  After a leap second the clock will no longer be
  210:  * reliable until it resynchronizes.  Hope 40 minutes is enough. */
  211: #define	EESLEAPHOLD	(40 * 60)
  212: 
  213: #define	EES_STEP_F	(1 << 24) /* the receiver steps in units of about 4ms */
  214: #define	EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
  215: #define	EES_STEP_NOTE	(1 << 21)/* Log any unexpected jumps, say .5 ms .... */
  216: #define	EES_STEP_NOTES	50	/* Only do a limited number */
  217: #define	MAX_STEP	16	/* Max number of steps to remember */
  218: 
  219:      /* debug is a bit mask of debugging that is wanted */
  220: #define	DB_SYSLOG_SMPLI		0x0001
  221: #define	DB_SYSLOG_SMPLE		0x0002
  222: #define	DB_SYSLOG_SMTHI		0x0004
  223: #define	DB_SYSLOG_NSMTHE	0x0008
  224: #define	DB_SYSLOG_NSMTHI	0x0010
  225: #define	DB_SYSLOG_SMTHE		0x0020
  226: #define	DB_PRINT_EV		0x0040
  227: #define	DB_PRINT_CDT		0x0080
  228: #define	DB_PRINT_CDTC		0x0100
  229: #define	DB_SYSLOG_KEEPD		0x0800
  230: #define	DB_SYSLOG_KEEPE		0x1000
  231: #define	DB_LOG_DELTAS		0x2000
  232: #define	DB_PRINT_DELTAS		0x4000
  233: #define	DB_LOG_AWAITMORE	0x8000
  234: #define	DB_LOG_SAMPLES		0x10000
  235: #define	DB_NO_PPS		0x20000
  236: #define	DB_INC_PPS		0x40000
  237: #define	DB_DUMP_DELTAS		0x80000
  238: 
  239:      struct eesunit {			/* EES unit control structure. */
  240: 	     struct peer *peer;		/* associated peer structure */
  241: 	     struct refclockio io;		/* given to the I/O handler */
  242: 	     l_fp	reftime;		/* reference time */
  243: 	     l_fp	lastsampletime;		/* time as in txt from last EES msg */
  244: 	     l_fp	arrvtime;		/* Time at which pkt arrived */
  245: 	     l_fp	codeoffsets[NCODES];	/* the time of arrival of 232 codes */
  246: 	     l_fp	offset;			/* chosen offset        (for clkbug) */
  247: 	     l_fp	lowoffset;		/* lowest sample offset (for clkbug) */
  248: 	     l_fp	highoffset;		/* highest   "     "    (for clkbug) */
  249: 	     char	lastcode[LENEESCODE+6];	/* last time code we received */
  250: 	     u_long	lasttime;		/* last time clock heard from */
  251: 	     u_long	clocklastgood;		/* last time good radio seen */
  252: 	     u_char	lencode;		/* length of code in buffer */
  253: 	     u_char	nsamples;		/* number of samples we've collected */
  254: 	     u_char	codestate;		/* state of 232 code reception */
  255: 	     u_char	unit;			/* unit number for this guy */
  256: 	     u_char	status;			/* clock status */
  257: 	     u_char	lastevent;		/* last clock event */
  258: 	     u_char	reason;			/* reason for last abort */
  259: 	     u_char	hour;			/* hour of day */
  260: 	     u_char	minute;			/* minute of hour */
  261: 	     u_char	second;			/* seconds of minute */
  262: 	     char	tz;			/* timezone from clock */
  263: 	     u_char	ttytype;		/* method used */
  264: 	     u_char	dump_vals;		/* Should clock values be dumped */
  265: 	     u_char	usealldata;		/* Use ALL samples */
  266: 	     u_short	day;			/* day of year from last code */
  267: 	     u_long	yearstart;		/* start of current year */
  268: 	     u_long	leaphold;		/* time of leap hold expiry */
  269: 	     u_long	badformat;		/* number of bad format codes */
  270: 	     u_long	baddata;		/* number of invalid time codes */
  271: 	     u_long	timestarted;		/* time we started this */
  272: 	     long	last_pps_no;		/* The serial # of the last PPS */
  273: 	     char	fix_pending;		/* Is a "sync to time" pending ? */
  274: 	     /* Fine tuning - compensate for 4 mS ramping .... */
  275: 	     l_fp	last_l;			/* last time stamp */
  276: 	     u_char	last_steps[MAX_STEP];	/* Most recent n steps */
  277: 	     int	best_av_step;		/* Best guess at average step */
  278: 	     char	best_av_step_count;	/* # of steps over used above */
  279: 	     char	this_step;		/* Current pos in buffer */
  280: 	     int	last_step_late;		/* How late the last step was (0-59) */
  281: 	     long	jump_fsecs;		/* # of fractions of a sec last jump */
  282: 	     u_long	last_step;		/* time of last step */
  283: 	     int	last_step_secs;		/* Number of seconds in last step */
  284: 	     int	using_ramp;		/* 1 -> noemal, -1 -> over stepped */
  285:      };
  286: #define	last_sec	last_l.l_ui
  287: #define	last_sfsec	last_l.l_f
  288: #define	this_uisec	((ees->arrvtime).l_ui)
  289: #define	this_sfsec	((ees->arrvtime).l_f)
  290: #define	msec(x)		((x) / (1<<22))
  291: #define	LAST_STEPS	(sizeof ees->last_steps / sizeof ees->last_steps[0])
  292: #define	subms(x)	((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
  293: 
  294: /* Bitmask for what methods to try to use -- currently only PPS enabled */
  295: #define	T_CBREAK	1
  296: #define	T_PPS		8
  297: /* macros to test above */
  298: #define	is_cbreak(x)	((x)->ttytype & T_CBREAK)
  299: #define	is_pps(x)	((x)->ttytype & T_PPS)
  300: #define	is_any(x)	((x)->ttytype)
  301: 
  302: #define	CODEREASON	20	/* reason codes */
  303: 
  304: /* Data space for the unit structures.  Note that we allocate these on
  305:  * the fly, but never give them back. */
  306: static struct eesunit *eesunits[MAXUNITS];
  307: static u_char unitinuse[MAXUNITS];
  308: 
  309: /* Keep the fudge factors separately so they can be set even
  310:  * when no clock is configured. */
  311: static l_fp inherent_delay[MAXUNITS];		/* when time stamp is taken */
  312: static l_fp fudgefactor[MAXUNITS];		/* fudgetime1 */
  313: static l_fp os_delay[MAXUNITS];			/* fudgetime2 */
  314: static l_fp offset_fudge[MAXUNITS];		/* Sum of above */
  315: static u_char stratumtouse[MAXUNITS];
  316: static u_char sloppyclockflag[MAXUNITS];
  317: 
  318: static int deltas[60];
  319: 
  320: static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
  321: static l_fp onesec; /* = { 1, 0 }; */
  322: 
  323: #ifndef	DUMP_BUF_SIZE	/* Size of buffer to be used by dump_buf */
  324: #define	DUMP_BUF_SIZE	10112
  325: #endif
  326: 
  327: /* ees_reset - reset the count back to zero */
  328: #define	ees_reset(ees) (ees)->nsamples = 0; \
  329: (ees)->codestate = EESCS_WAIT
  330: 
  331: /* ees_event - record and report an event */
  332: #define	ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
  333: ees_report_event((ees), (evcode))
  334: 
  335:      /* Find the precision of the system clock by reading it */
  336: #define	USECS	1000000
  337: #define	MINSTEP	5	/* some systems increment uS on each call */
  338: #define	MAXLOOPS (USECS/9)
  339: 
  340: /*
  341:  * Function prototypes
  342:  */
  343: 
  344: static	int	msfees_start	P((int unit, struct peer *peer));
  345: static	void	msfees_shutdown	P((int unit, struct peer *peer));
  346: static	void	msfees_poll	P((int unit, struct peer *peer));
  347: static	void	msfees_init	P((void));
  348: static	void	dump_buf	P((l_fp *coffs, int from, int to, char *text));
  349: static	void	ees_report_event P((struct eesunit *ees, int code));
  350: static	void	ees_receive	P((struct recvbuf *rbufp));
  351: static	void	ees_process	P((struct eesunit *ees));
  352: #ifdef QSORT_USES_VOID_P
  353: static	int	offcompare	P((const void *va, const void *vb));
  354: #else
  355: static	int	offcompare	P((const l_fp *a, const l_fp *b));
  356: #endif /* QSORT_USES_VOID_P */
  357: 
  358: 
  359: /*
  360:  * Transfer vector
  361:  */
  362: struct	refclock refclock_msfees = {
  363: 	msfees_start,		/* start up driver */
  364: 	msfees_shutdown,	/* shut down driver */
  365: 	msfees_poll,		/* transmit poll message */
  366: 	noentry,		/* not used */
  367: 	msfees_init,		/* initialize driver */
  368: 	noentry,		/* not used */
  369: 	NOFLAGS			/* not used */
  370: };
  371: 
  372: 
  373: static void
  374: dump_buf(
  375: 	l_fp *coffs,
  376: 	int from,
  377: 	int to,
  378: 	char *text
  379: 	)
  380: {
  381: 	char buff[DUMP_BUF_SIZE + 80];
  382: 	int i;
  383: 	register char *ptr = buff;
  384: 
  385: 	snprintf(buff, sizeof(buff), text);
  386: 	for (i = from; i < to; i++) {
  387: 		ptr += strlen(ptr);
  388: 		if ((ptr - buff) > DUMP_BUF_SIZE) {
  389: 			msyslog(LOG_DEBUG, "D: %s", buff);
  390: 			ptr = buff;
  391: 		}
  392: 		snprintf(ptr, sizeof(buff) - (ptr - buff),
  393: 			 " %06d", ((int)coffs[i].l_f) / 4295);
  394: 	}
  395: 	msyslog(LOG_DEBUG, "D: %s", buff);
  396: }
  397: 
  398: /* msfees_init - initialize internal ees driver data */
  399: static void
  400: msfees_init(void)
  401: {
  402: 	register int i;
  403: 	/* Just zero the data arrays */
  404: 	memset((char *)eesunits, 0, sizeof eesunits);
  405: 	memset((char *)unitinuse, 0, sizeof unitinuse);
  406: 
  407: 	acceptable_slop.l_ui = 0;
  408: 	acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
  409: 
  410: 	onesec.l_ui = 1;
  411: 	onesec.l_uf = 0;
  412: 
  413: 	/* Initialize fudge factors to default. */
  414: 	for (i = 0; i < MAXUNITS; i++) {
  415: 		fudgefactor[i].l_ui	= 0;
  416: 		fudgefactor[i].l_uf	= DEFFUDGETIME;
  417: 		os_delay[i].l_ui	= 0;
  418: 		os_delay[i].l_uf	= DEFOSTIME;
  419: 		inherent_delay[i].l_ui	= 0;
  420: 		inherent_delay[i].l_uf	= DEFINHTIME;
  421: 		offset_fudge[i]		= os_delay[i];
  422: 		L_ADD(&offset_fudge[i], &fudgefactor[i]);
  423: 		L_ADD(&offset_fudge[i], &inherent_delay[i]);
  424: 		stratumtouse[i]		= 0;
  425: 		sloppyclockflag[i]	= 0;
  426: 	}
  427: }
  428: 
  429: 
  430: /* msfees_start - open the EES devices and initialize data for processing */
  431: static int
  432: msfees_start(
  433: 	int unit,
  434: 	struct peer *peer
  435: 	)
  436: {
  437: 	register struct eesunit *ees;
  438: 	register int i;
  439: 	int fd232 = -1;
  440: 	char eesdev[20];
  441: 	struct termios ttyb, *ttyp;
  442: 	struct refclockproc *pp;
  443: 	pp = peer->procptr;
  444: 
  445: 	if (unit >= MAXUNITS) {
  446: 		msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
  447: 			unit, MAXUNITS-1);
  448: 		return 0;
  449: 	}
  450: 	if (unitinuse[unit]) {
  451: 		msyslog(LOG_ERR, "ees clock: unit number %d in use", unit);
  452: 		return 0;
  453: 	}
  454: 
  455: 	/* Unit okay, attempt to open the devices.  We do them both at
  456: 	 * once to make sure we can */
  457: 	snprintf(eesdev, sizeof(eesdev), EES232, unit);
  458: 
  459: 	fd232 = open(eesdev, O_RDWR, 0777);
  460: 	if (fd232 == -1) {
  461: 		msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
  462: 		return 0;
  463: 	}
  464: 
  465: #ifdef	TIOCEXCL
  466: 	/* Set for exclusive use */
  467: 	if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
  468: 		msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
  469: 		goto screwed;
  470: 	}
  471: #endif
  472: 
  473: 	/* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
  474: 
  475: 	/* Set port characteristics.  If we don't have a STREAMS module or
  476: 	 * a clock line discipline, cooked mode is just usable, even though it
  477: 	 * strips the top bit.  The only EES byte which uses the top
  478: 	 * bit is the year, and we don't use that anyway. If we do
  479: 	 * have the line discipline, we choose raw mode, and the
  480: 	 * line discipline code will block up the messages.
  481: 	 */
  482: 
  483: 	/* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
  484: 
  485: 	ttyp = &ttyb;
  486: 	if (tcgetattr(fd232, ttyp) < 0) {
  487: 		msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
  488: 		goto screwed;
  489: 	}
  490: 
  491: 	ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
  492: 	ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
  493: 	ttyp->c_oflag = 0;
  494: 	ttyp->c_lflag = ICANON;
  495: 	ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
  496: 	if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
  497: 		msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
  498: 		goto screwed;
  499: 	}
  500: 
  501: 	if (tcflush(fd232, TCIOFLUSH) < 0) {
  502: 		msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
  503: 		goto screwed;
  504: 	}
  505: 
  506: 	inherent_delay[unit].l_uf = INH_DELAY_PPS;
  507: 
  508: 	/* offset fudge (how *late* the timestamp is) = fudge + os delays */
  509: 	offset_fudge[unit] = os_delay[unit];
  510: 	L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
  511: 	L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
  512: 
  513: 	/* Looks like this might succeed.  Find memory for the structure.
  514: 	 * Look to see if there are any unused ones, if not we malloc() one.
  515: 	 */
  516: 	if (eesunits[unit] != 0) /* The one we want is okay */
  517: 	    ees = eesunits[unit];
  518: 	else {
  519: 		/* Look for an unused, but allocated struct */
  520: 		for (i = 0; i < MAXUNITS; i++) {
  521: 			if (!unitinuse[i] && eesunits[i] != 0)
  522: 			    break;
  523: 		}
  524: 
  525: 		if (i < MAXUNITS) {	/* Reclaim this one */
  526: 			ees = eesunits[i];
  527: 			eesunits[i] = 0;
  528: 		}			/* no spare -- make a new one */
  529: 		else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
  530: 	}
  531: 	memset((char *)ees, 0, sizeof(struct eesunit));
  532: 	eesunits[unit] = ees;
  533: 
  534: 	/* Set up the structures */
  535: 	ees->peer	= peer;
  536: 	ees->unit	= (u_char)unit;
  537: 	ees->timestarted= current_time;
  538: 	ees->ttytype	= 0;
  539: 	ees->io.clock_recv= ees_receive;
  540: 	ees->io.srcclock= (caddr_t)ees;
  541: 	ees->io.datalen	= 0;
  542: 	ees->io.fd	= fd232;
  543: 
  544: 	/* Okay.  Push one of the two (linked into the kernel, or dynamically
  545: 	 * loaded) STREAMS module, and give it to the I/O code to start
  546: 	 * receiving stuff.
  547: 	 */
  548: 
  549: #ifdef STREAM
  550: 	{
  551: 		int rc1;
  552: 		/* Pop any existing onews first ... */
  553: 		while (ioctl(fd232, I_POP, 0 ) >= 0) ;
  554: 
  555: 		/* Now try pushing either of the possible modules */
  556: 		if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
  557: 		    ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
  558: 			msyslog(LOG_ERR,
  559: 				"ees clock: Push of `%s' and `%s' to %s failed %m",
  560: 				STREAM_PP1, STREAM_PP2, eesdev);
  561: 			goto screwed;
  562: 		}
  563: 		else {
  564: 			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
  565: 				msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
  566: 					(rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
  567: 			ees->ttytype |= T_PPS;
  568: 		}
  569: 	}
  570: #endif /* STREAM */
  571: 
  572: 	/* Add the clock */
  573: 	if (!io_addclock(&ees->io)) {
  574: 		/* Oh shit.  Just close and return. */
  575: 		msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
  576: 		goto screwed;
  577: 	}
  578: 
  579: 
  580: 	/* All done.  Initialize a few random peer variables, then
  581: 	 * return success. */
  582: 	peer->precision	= sys_precision;
  583: 	peer->stratum	= stratumtouse[unit];
  584: 	if (stratumtouse[unit] <= 1) {
  585: 		memcpy((char *)&pp->refid, EESREFID, 4);
  586: 		if (unit > 0 && unit < 10)
  587: 		    ((char *)&pp->refid)[3] = '0' + unit;
  588: 	} else {
  589: 		peer->refid = htonl(EESHSREFID);
  590: 	}
  591: 	unitinuse[unit] = 1;
  592: 	pp->unitptr = (caddr_t) &eesunits[unit];
  593: 	pp->clockdesc = EESDESCRIPTION;
  594: 	msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
  595: 	return (1);
  596: 
  597:     screwed:
  598: 	if (fd232 != -1)
  599: 	    (void) close(fd232);
  600: 	return (0);
  601: }
  602: 
  603: 
  604: /* msfees_shutdown - shut down a EES clock */
  605: static void
  606: msfees_shutdown(
  607: 	int unit,
  608: 	struct peer *peer
  609: 	)
  610: {
  611: 	register struct eesunit *ees;
  612: 
  613: 	if (unit >= MAXUNITS) {
  614: 		msyslog(LOG_ERR,
  615: 			"ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
  616: 			unit, MAXUNITS);
  617: 		return;
  618: 	}
  619: 	if (!unitinuse[unit]) {
  620: 		msyslog(LOG_ERR,
  621: 			"ees clock: INTERNAL ERROR, unit number %d not in use", unit);
  622: 		return;
  623: 	}
  624: 
  625: 	/* Tell the I/O module to turn us off.  We're history. */
  626: 	ees = eesunits[unit];
  627: 	io_closeclock(&ees->io);
  628: 	unitinuse[unit] = 0;
  629: }
  630: 
  631: 
  632: /* ees_report_event - note the occurance of an event */
  633: static void
  634: ees_report_event(
  635: 	struct eesunit *ees,
  636: 	int code
  637: 	)
  638: {
  639: 	if (ees->status != (u_char)code) {
  640: 		ees->status = (u_char)code;
  641: 		if (code != CEVNT_NOMINAL)
  642: 		    ees->lastevent = (u_char)code;
  643: 		/* Should report event to trap handler in here.
  644: 		 * Soon...
  645: 		 */
  646: 	}
  647: }
  648: 
  649: 
  650: /* ees_receive - receive data from the serial interface on an EES clock */
  651: static void
  652: ees_receive(
  653: 	struct recvbuf *rbufp
  654: 	)
  655: {
  656: 	register int n_sample;
  657: 	register int day;
  658: 	register struct eesunit *ees;
  659: 	register u_char *dpt;		/* Data PoinTeR: move along ... */
  660: 	register u_char *dpend;		/* Points just *after* last data char */
  661: 	register char *cp;
  662: 	l_fp tmp;
  663: 	int call_pps_sample = 0;
  664: 	l_fp pps_arrvstamp;
  665: 	int	sincelast;
  666: 	int	pps_step = 0;
  667: 	int	suspect_4ms_step = 0;
  668: 	struct ppsclockev ppsclockev;
  669: 	long *ptr = (long *) &ppsclockev;
  670: 	int rc;
  671: 	int request;
  672: #ifdef HAVE_CIOGETEV
  673: 	request = CIOGETEV;
  674: #endif
  675: #ifdef HAVE_TIOCGPPSEV
  676: 	request = TIOCGPPSEV;
  677: #endif
  678: 
  679: 	/* Get the clock this applies to and a pointer to the data */
  680: 	ees = (struct eesunit *)rbufp->recv_srcclock;
  681: 	dpt = (u_char *)&rbufp->recv_space;
  682: 	dpend = dpt + rbufp->recv_length;
  683: 	if ((dbg & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
  684: 	    printf("[%d] ", rbufp->recv_length);
  685: 
  686: 	/* Check out our state and process appropriately */
  687: 	switch (ees->codestate) {
  688: 	    case EESCS_WAIT:
  689: 		/* Set an initial guess at the timestamp as the recv time.
  690: 		 * If just running in CBREAK mode, we can't improve this.
  691: 		 * If we have the CLOCK Line Discipline, PPSCD, or sime such,
  692: 		 * then we will do better later ....
  693: 		 */
  694: 		ees->arrvtime = rbufp->recv_time;
  695: 		ees->codestate = EESCS_GOTSOME;
  696: 		ees->lencode = 0;
  697: 		/*FALLSTHROUGH*/
  698: 
  699: 	    case EESCS_GOTSOME:
  700: 		cp = &(ees->lastcode[ees->lencode]);
  701: 
  702: 		/* Gobble the bytes until the final (possibly stripped) 0xff */
  703: 		while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
  704: 			*cp++ = (char)*dpt++;
  705: 			ees->lencode++;
  706: 			/* Oh dear -- too many bytes .. */
  707: 			if (ees->lencode > LENEESPRT) {
  708: 				NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
  709: 					msyslog(LOG_INFO,
  710: 						"I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
  711: 						ees->lencode, dpend - dpt, LENEESPRT,
  712: #define D(x) (ees->lastcode[x])
  713: 						D(0), D(1), D(2), D(3), D(4), D(5), D(6),
  714: 						D(7), D(8), D(9), D(10), D(11), D(12));
  715: #undef	D
  716: 				ees->badformat++;
  717: 				ees->reason = CODEREASON + 1;
  718: 				ees_event(ees, CEVNT_BADREPLY);
  719: 				ees_reset(ees);
  720: 				return;
  721: 			}
  722: 		}
  723: 		/* Gave up because it was end of the buffer, rather than ff */
  724: 		if (dpt == dpend) {
  725: 			/* Incomplete.  Wait for more. */
  726: 			if (dbg & DB_LOG_AWAITMORE)
  727: 			    msyslog(LOG_INFO,
  728: 				    "I: ees clock %d: %p == %p: await more",
  729: 				    ees->unit, dpt, dpend);
  730: 			return;
  731: 		}
  732: 
  733: 		/* This shouldn't happen ... ! */
  734: 		if ((*dpt & 0x7f) != 0x7f) {
  735: 			msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
  736: 			ees->badformat++;
  737: 			ees->reason = CODEREASON + 2;
  738: 			ees_event(ees, CEVNT_BADREPLY);
  739: 			ees_reset(ees);
  740: 			return;
  741: 		}
  742: 
  743: 		/* Skip the 0xff */
  744: 		dpt++;
  745: 
  746: 		/* Finally, got a complete buffer.  Mainline code will
  747: 		 * continue on. */
  748: 		cp = ees->lastcode;
  749: 		break;
  750: 
  751: 	    default:
  752: 		msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
  753: 			ees->unit, ees->codestate);
  754: 		ees->reason = CODEREASON + 5;
  755: 		ees_event(ees, CEVNT_FAULT);
  756: 		ees_reset(ees);
  757: 		return;
  758: 	}
  759: 
  760: 	/* Boy!  After all that crap, the lastcode buffer now contains
  761: 	 * something we hope will be a valid time code.  Do length
  762: 	 * checks and sanity checks on constant data.
  763: 	 */
  764: 	ees->codestate = EESCS_WAIT;
  765: 	ees->lasttime = current_time;
  766: 	if (ees->lencode != LENEESPRT) {
  767: 		ees->badformat++;
  768: 		ees->reason = CODEREASON + 6;
  769: 		ees_event(ees, CEVNT_BADREPLY);
  770: 		ees_reset(ees);
  771: 		return;
  772: 	}
  773: 
  774: 	cp = ees->lastcode;
  775: 
  776: 	/* Check that centisecond is zero */
  777: 	if (cp[EESM_CSEC] != 0) {
  778: 		ees->baddata++;
  779: 		ees->reason = CODEREASON + 7;
  780: 		ees_event(ees, CEVNT_BADREPLY);
  781: 		ees_reset(ees);
  782: 		return;
  783: 	}
  784: 
  785: 	/* Check flag formats */
  786: 	if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
  787: 		ees->badformat++;
  788: 		ees->reason = CODEREASON + 8;
  789: 		ees_event(ees, CEVNT_BADREPLY);
  790: 		ees_reset(ees);
  791: 		return;
  792: 	}
  793: 
  794: 	if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
  795: 		ees->badformat++;
  796: 		ees->reason = CODEREASON + 9;
  797: 		ees_event(ees, CEVNT_BADREPLY);
  798: 		ees_reset(ees);
  799: 		return;
  800: 	}
  801: 
  802: 	if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
  803: 		ees->badformat++;
  804: 		ees->reason = CODEREASON + 10;
  805: 		ees_event(ees, CEVNT_BADREPLY);
  806: 		ees_reset(ees);
  807: 		return;
  808: 	}
  809: 
  810: 	/* So far, so good.  Compute day, hours, minutes, seconds,
  811: 	 * time zone.  Do range checks on these.
  812: 	 */
  813: 
  814: #define bcdunpack(val)	( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
  815: #define istrue(x)	((x)?1:0)
  816: 
  817: 	ees->second  = bcdunpack(cp[EESM_SEC]);  /* second       */
  818: 	ees->minute  = bcdunpack(cp[EESM_MIN]);  /* minute       */
  819: 	ees->hour    = bcdunpack(cp[EESM_HOUR]); /* hour         */
  820: 
  821: 	day          = bcdunpack(cp[EESM_DAY]);  /* day of month */
  822: 
  823: 	switch (bcdunpack(cp[EESM_MON])) {       /* month        */
  824: 
  825: 		/*  Add in lengths of all previous months.  Add one more
  826: 		    if it is a leap year and after February.
  827: 		*/
  828: 	    case 12:	day += NOV;			  /*FALLSTHROUGH*/
  829: 	    case 11:	day += OCT;			  /*FALLSTHROUGH*/
  830: 	    case 10:	day += SEP;			  /*FALLSTHROUGH*/
  831: 	    case  9:	day += AUG;			  /*FALLSTHROUGH*/
  832: 	    case  8:	day += JUL;			  /*FALLSTHROUGH*/
  833: 	    case  7:	day += JUN;			  /*FALLSTHROUGH*/
  834: 	    case  6:	day += MAY;			  /*FALLSTHROUGH*/
  835: 	    case  5:	day += APR;			  /*FALLSTHROUGH*/
  836: 	    case  4:	day += MAR;			  /*FALLSTHROUGH*/
  837: 	    case  3:	day += FEB;
  838: 		if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
  839: 	    case  2:	day += JAN;			  /*FALLSTHROUGH*/
  840: 	    case  1:	break;
  841: 	    default:	ees->baddata++;
  842: 		ees->reason = CODEREASON + 11;
  843: 		ees_event(ees, CEVNT_BADDATE);
  844: 		ees_reset(ees);
  845: 		return;
  846: 	}
  847: 
  848: 	ees->day     = day;
  849: 
  850: 	/* Get timezone. The clocktime routine wants the number
  851: 	 * of hours to add to the delivered time to get UT.
  852: 	 * Currently -1 if BST flag set, 0 otherwise.  This
  853: 	 * is the place to tweak things if double summer time
  854: 	 * ever happens.
  855: 	 */
  856: 	ees->tz      = istrue(cp[EESM_BST]) ? -1 : 0;
  857: 
  858: 	if (ees->day > 366 || ees->day < 1 ||
  859: 	    ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
  860: 		ees->baddata++;
  861: 		ees->reason = CODEREASON + 12;
  862: 		ees_event(ees, CEVNT_BADDATE);
  863: 		ees_reset(ees);
  864: 		return;
  865: 	}
  866: 
  867: 	n_sample = ees->nsamples;
  868: 
  869: 	/* Now, compute the reference time value: text -> tmp.l_ui */
  870: 	if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
  871: 		       ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
  872: 		       &tmp.l_ui)) {
  873: 		ees->baddata++;
  874: 		ees->reason = CODEREASON + 13;
  875: 		ees_event(ees, CEVNT_BADDATE);
  876: 		ees_reset(ees);
  877: 		return;
  878: 	}
  879: 	tmp.l_uf = 0;
  880: 
  881: 	/*  DON'T use ees->arrvtime -- it may be < reftime */
  882: 	ees->lastsampletime = tmp;
  883: 
  884: 	/* If we are synchronised to the radio, update the reference time.
  885: 	 * Also keep a note of when clock was last good.
  886: 	 */
  887: 	if (istrue(cp[EESM_MSFOK])) {
  888: 		ees->reftime = tmp;
  889: 		ees->clocklastgood = current_time;
  890: 	}
  891: 
  892: 
  893: 	/* Compute the offset.  For the fractional part of the
  894: 	 * offset we use the expected delay for the message.
  895: 	 */
  896: 	ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
  897: 	ees->codeoffsets[n_sample].l_uf = 0;
  898: 
  899: 	/* Number of seconds since the last step */
  900: 	sincelast = this_uisec - ees->last_step;
  901: 
  902: 	memset((char *) &ppsclockev, 0, sizeof ppsclockev);
  903: 
  904: 	rc = ioctl(ees->io.fd, request, (char *) &ppsclockev);
  905: 	if (dbg & DB_PRINT_EV) fprintf(stderr,
  906: 					 "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n",
  907: 					 DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees),
  908: 					 rc, errno, ptr[0], ptr[1], ptr[2]);
  909: 
  910: 	/* If we managed to get the time of arrival, process the info */
  911: 	if (rc >= 0) {
  912: 		int conv = -1;
  913: 		pps_step = ppsclockev.serial - ees->last_pps_no;
  914: 
  915: 		/* Possible that PPS triggered, but text message didn't */
  916: 		if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
  917: 		if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
  918: 		if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
  919: 
  920: 		/* allow for single loss of PPS only */
  921: 		if (pps_step != 1 && pps_step != 2)
  922: 		    fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
  923: 			    ppsclockev.serial, ees->last_pps_no, pps_step);
  924: 		else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
  925: 		    fprintf(stderr, "buftvtots failed\n");
  926: 		else {	/* if ((ABS(time difference) - 0.25) < 0)
  927: 			 * then believe it ...
  928: 			 */
  929: 			l_fp diff;
  930: 			diff = pps_arrvstamp;
  931: 			conv = 0;
  932: 			L_SUB(&diff, &ees->arrvtime);
  933: 			if (dbg & DB_PRINT_CDT)
  934: 			    printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s",
  935: 				   DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf,
  936: 				   (long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf,
  937: 				   (long)diff.l_ui, (long)diff.l_uf,
  938: 				   ctime(&(ppsclockev.tv.tv_sec)));
  939: 			if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
  940: 			L_SUB(&diff, &acceptable_slop);
  941: 			if (L_ISNEG(&diff)) {	/* AOK -- pps_sample */
  942: 				ees->arrvtime = pps_arrvstamp;
  943: 				conv++;
  944: 				call_pps_sample++;
  945: 			}
  946: 			/* Some loss of some signals around sec = 1 */
  947: 			else if (ees->second == 1) {
  948: 				diff = pps_arrvstamp;
  949: 				L_ADD(&diff, &onesec);
  950: 				L_SUB(&diff, &ees->arrvtime);
  951: 				if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
  952: 				L_SUB(&diff, &acceptable_slop);
  953: 				msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
  954: 					pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
  955: 					pps_arrvstamp.l_uf,
  956: 					ees->arrvtime.l_uf,
  957: 					diff.l_ui, diff.l_uf,
  958: 					(int)ppsclockev.tv.tv_usec,
  959: 					ctime(&(ppsclockev.tv.tv_sec)));
  960: 				if (L_ISNEG(&diff)) {	/* AOK -- pps_sample */
  961: 					suspect_4ms_step |= 2;
  962: 					ees->arrvtime = pps_arrvstamp;
  963: 					L_ADD(&ees->arrvtime, &onesec);
  964: 					conv++;
  965: 					call_pps_sample++;
  966: 				}
  967: 			}
  968: 		}
  969: 		ees->last_pps_no = ppsclockev.serial;
  970: 		if (dbg & DB_PRINT_CDTC)
  971: 		    printf(
  972: 			    "[%x] %08lx %08lx %d u%d (%d %d)\n",
  973: 			    DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui,
  974: 			    (long)pps_arrvstamp.l_uf, conv, ees->unit,
  975: 			    call_pps_sample, pps_step);
  976: 	}
  977: 
  978: 	/* See if there has been a 4ms jump at a minute boundry */
  979: 	{	l_fp	delta;
  980: #define	delta_isec	delta.l_ui
  981: #define	delta_ssec	delta.l_i
  982: #define	delta_sfsec	delta.l_f
  983: 	long	delta_f_abs;
  984: 
  985: 	delta.l_i = ees->arrvtime.l_i;
  986: 	delta.l_f = ees->arrvtime.l_f;
  987: 
  988: 	L_SUB(&delta, &ees->last_l);
  989: 	delta_f_abs = delta_sfsec;
  990: 	if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
  991: 
  992: 	/* Dump the deltas each minute */
  993: 	if (dbg & DB_DUMP_DELTAS)
  994: 	{	
  995: 		if (/*0 <= ees->second && */
  996: 		    ees->second < COUNTOF(deltas))
  997: 			deltas[ees->second] = delta_sfsec;
  998: 	/* Dump on second 1, as second 0 sometimes missed */
  999: 	if (ees->second == 1) {
 1000: 		char text[16 * COUNTOF(deltas)];
 1001: 		char *cptr=text;
 1002: 		int i;
 1003: 		for (i = 0; i < COUNTOF(deltas); i++) {
 1004: 			snprintf(cptr, sizeof(text) / COUNTOF(deltas),
 1005: 				" %d.%04d", msec(deltas[i]),
 1006: 				subms(deltas[i]));
 1007: 			cptr += strlen(cptr);
 1008: 		}
 1009: 		msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
 1010: 			msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
 1011: 			msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
 1012: 			text+1);
 1013: 		for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
 1014: 	}
 1015: 	}
 1016: 
 1017: 	/* Lets see if we have a 4 mS step at a minute boundaary */
 1018: 	if (	((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
 1019: 		(delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
 1020: 		(ees->second == 0 || ees->second == 1 || ees->second == 2) &&
 1021: 		(sincelast < 0 || sincelast > 122)
 1022: 		) {	/* 4ms jump at min boundry */
 1023: 		int old_sincelast;
 1024: 		int count=0;
 1025: 		int sum = 0;
 1026: 		/* Yes -- so compute the ramp time */
 1027: 		if (ees->last_step == 0) sincelast = 0;
 1028: 		old_sincelast = sincelast;
 1029: 
 1030: 		/* First time in, just set "ees->last_step" */
 1031: 		if(ees->last_step) {
 1032: 			int other_step = 0;
 1033: 			int third_step = 0;
 1034: 			int this_step = (sincelast + (60 /2)) / 60;
 1035: 			int p_step = ees->this_step;
 1036: 			int p;
 1037: 			ees->last_steps[p_step] = this_step;
 1038: 			p= p_step;
 1039: 			p_step++;
 1040: 			if (p_step >= LAST_STEPS) p_step = 0;
 1041: 			ees->this_step = p_step;
 1042: 				/* Find the "average" interval */
 1043: 			while (p != p_step) {
 1044: 				int this = ees->last_steps[p];
 1045: 				if (this == 0) break;
 1046: 				if (this != this_step) {
 1047: 					if (other_step == 0 && (
 1048: 						this== (this_step +2) ||
 1049: 						this== (this_step -2) ||
 1050: 						this== (this_step +1) ||
 1051: 						this== (this_step -1)))
 1052: 					    other_step = this;
 1053: 					if (other_step != this) {
 1054: 						int idelta = (this_step - other_step);
 1055: 						if (idelta < 0) idelta = - idelta;
 1056: 						if (third_step == 0 && (
 1057: 							(idelta == 1) ? (
 1058: 								this == (other_step +1) ||
 1059: 								this == (other_step -1) ||
 1060: 								this == (this_step +1) ||
 1061: 								this == (this_step -1))
 1062: 							:
 1063: 							(
 1064: 								this == (this_step + other_step)/2
 1065: 								)
 1066: 							)) third_step = this;
 1067: 						if (third_step != this) break;
 1068: 					}
 1069: 				}
 1070: 				sum += this;
 1071: 				p--;
 1072: 				if (p < 0) p += LAST_STEPS;
 1073: 				count++;
 1074: 			}
 1075: 			msyslog(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);
 1076: 			if (count != 0) sum = ((sum * 60) + (count /2)) / count;
 1077: #define	SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
 1078: 			msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
 1079: 				ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
 1080: 				SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
 1081: 			printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
 1082: 			       ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
 1083: 			       SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
 1084: #undef SV
 1085: 			ees->jump_fsecs = delta_sfsec;
 1086: 			ees->using_ramp = 1;
 1087: 			if (sincelast > 170)
 1088: 			    ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
 1089: 			else ees->last_step_late = 30;
 1090: 			if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
 1091: 			if (ees->last_step_late < 0) ees->last_step_late = 0;
 1092: 			if (ees->last_step_late >= 60) ees->last_step_late = 59;
 1093: 			sincelast = 0;
 1094: 		}
 1095: 		else {	/* First time in -- just save info */
 1096: 			ees->last_step_late = 30;
 1097: 			ees->jump_fsecs = delta_sfsec;
 1098: 			ees->using_ramp = 1;
 1099: 			sum = 4 * 60;
 1100: 		}
 1101: 		ees->last_step = this_uisec;
 1102: 		printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n",
 1103: 		       ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
 1104: 		       ees->second, old_sincelast, ees->last_step_late, count, sum,
 1105: 		       ees->last_step_secs);
 1106: 		msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
 1107: 			ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second,
 1108: 			old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
 1109: 		if (sum) ees->last_step_secs = sum;
 1110: 	}
 1111: 	/* OK, so not a 4ms step at a minute boundry */
 1112: 	else {
 1113: 		if (suspect_4ms_step) msyslog(LOG_ERR,
 1114: 					      "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
 1115: 					      ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
 1116: 					      msec(EES_STEP_F - EES_STEP_F_GRACE),
 1117: 					      subms(EES_STEP_F - EES_STEP_F_GRACE),
 1118: 					      (int)msec(delta_f_abs),
 1119: 					      (int)subms(delta_f_abs),
 1120: 					      msec(EES_STEP_F + EES_STEP_F_GRACE),
 1121: 					      subms(EES_STEP_F + EES_STEP_F_GRACE),
 1122: 					      ees->second,
 1123: 					      sincelast);
 1124: 		if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
 1125: 			static int ees_step_notes = EES_STEP_NOTES;
 1126: 			if (ees_step_notes > 0) {
 1127: 				ees_step_notes--;
 1128: 				printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n",
 1129: 				       ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
 1130: 				       ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
 1131: 				msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
 1132: 					ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
 1133: 			}
 1134: 		}
 1135: 	}
 1136: 	}
 1137: 	ees->last_l = ees->arrvtime;
 1138: 
 1139: 	/* IF we have found that it's ramping
 1140: 	 * && it's within twice the expected ramp period
 1141: 	 * && there is a non zero step size (avoid /0 !)
 1142: 	 * THEN we twiddle things
 1143: 	 */
 1144: 	if (ees->using_ramp &&
 1145: 	    sincelast < (ees->last_step_secs)*2 &&
 1146: 	    ees->last_step_secs)
 1147: 	{	long	sec_of_ramp = sincelast + ees->last_step_late;
 1148: 	long	fsecs;
 1149: 	l_fp	inc;
 1150: 
 1151: 	/* Ramp time may vary, so may ramp for longer than last time */
 1152: 	if (sec_of_ramp > (ees->last_step_secs + 120))
 1153: 	    sec_of_ramp =  ees->last_step_secs;
 1154: 
 1155: 	/* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
 1156: 	fsecs = sec_of_ramp * (ees->jump_fsecs /  ees->last_step_secs);
 1157: 
 1158: 	if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
 1159: 					   "[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)",
 1160: 					   DB_LOG_DELTAS,
 1161: 					   ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
 1162: 					   pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
 1163: 	if (dbg & DB_PRINT_DELTAS) printf(
 1164: 		"MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n",
 1165: 		ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
 1166: 		(long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
 1167: 
 1168: 	/* Must sign extend the result */
 1169: 	inc.l_i = (fsecs < 0) ? -1 : 0;
 1170: 	inc.l_f = fsecs;
 1171: 	if (dbg & DB_INC_PPS)
 1172: 	{	L_SUB(&pps_arrvstamp, &inc);
 1173: 	L_SUB(&ees->arrvtime, &inc);
 1174: 	}
 1175: 	else
 1176: 	{	L_ADD(&pps_arrvstamp, &inc);
 1177: 	L_ADD(&ees->arrvtime, &inc);
 1178: 	}
 1179: 	}
 1180: 	else {
 1181: 		if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
 1182: 						   "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
 1183: 						   DB_LOG_DELTAS,
 1184: 						   ees->unit, ees->using_ramp,
 1185: 						   sincelast,
 1186: 						   (ees->last_step_secs)*2,
 1187: 						   ees->last_step_secs);
 1188: 		if (dbg & DB_PRINT_DELTAS) printf(
 1189: 			"[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
 1190: 			DB_LOG_DELTAS,
 1191: 			ees->unit, ees->using_ramp,
 1192: 			sincelast,
 1193: 			(ees->last_step_secs)*2,
 1194: 			ees->last_step_secs);
 1195: 	}
 1196: 
 1197: 	L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
 1198: 	L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
 1199: 
 1200: 	if (call_pps_sample && !(dbg & DB_NO_PPS)) {
 1201: 		/* Sigh -- it expects its args negated */
 1202: 		L_NEG(&pps_arrvstamp);
 1203: 		/*
 1204: 		 * I had to disable this here, since it appears there is no pointer to the
 1205: 		 * peer structure.
 1206: 		 *
 1207: 		 (void) pps_sample(peer, &pps_arrvstamp);
 1208: 		*/
 1209: 	}
 1210: 
 1211: 	/* Subtract off the local clock time stamp */
 1212: 	L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
 1213: 	if (dbg & DB_LOG_SAMPLES) msyslog(LOG_ERR,
 1214: 					    "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
 1215: 					    ees->unit, DB_LOG_DELTAS, n_sample,
 1216: 					    ees->codeoffsets[n_sample].l_f,
 1217: 					    ees->codeoffsets[n_sample].l_f / 4295,
 1218: 					    pps_arrvstamp.l_f,
 1219: 					    pps_arrvstamp.l_f /4295,
 1220: 					    (dbg & DB_NO_PPS) ? " [no PPS]" : "");
 1221: 
 1222: 	if (ees->nsamples++ == NCODES-1) ees_process(ees);
 1223: 
 1224: 	/* Done! */
 1225: }
 1226: 
 1227: 
 1228: /* offcompare - auxiliary comparison routine for offset sort */
 1229: 
 1230: #ifdef QSORT_USES_VOID_P
 1231: static int
 1232: offcompare(
 1233: 	const void *va,
 1234: 	const void *vb
 1235: 	)
 1236: {
 1237: 	const l_fp *a = (const l_fp *)va;
 1238: 	const l_fp *b = (const l_fp *)vb;
 1239: 	return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
 1240: }
 1241: #else
 1242: static int
 1243: offcompare(
 1244: 	const l_fp *a,
 1245: 	const l_fp *b
 1246: 	)
 1247: {
 1248: 	return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
 1249: }
 1250: #endif /* QSORT_USES_VOID_P */
 1251: 
 1252: 
 1253: /* ees_process - process a pile of samples from the clock */
 1254: static void
 1255: ees_process(
 1256: 	struct eesunit *ees
 1257: 	)
 1258: {
 1259: 	static int last_samples = -1;
 1260: 	register int i, j;
 1261: 	register int noff;
 1262: 	register l_fp *coffs = ees->codeoffsets;
 1263: 	l_fp offset, tmp;
 1264: 	double dispersion;	/* ++++ */
 1265: 	int lostsync, isinsync;
 1266: 	int samples = ees->nsamples;
 1267: 	int samplelog = 0;	/* keep "gcc -Wall" happy ! */
 1268: 	int samplereduce = (samples + 1) / 2;
 1269: 	double doffset;
 1270: 
 1271: 	/* Reset things to zero so we don't have to worry later */
 1272: 	ees_reset(ees);
 1273: 
 1274: 	if (sloppyclockflag[ees->unit]) {
 1275: 		samplelog = (samples <  2) ? 0 :
 1276: 			(samples <  5) ? 1 :
 1277: 			(samples <  9) ? 2 :
 1278: 			(samples < 17) ? 3 :
 1279: 			(samples < 33) ? 4 : 5;
 1280: 		samplereduce = (1 << samplelog);
 1281: 	}
 1282: 
 1283: 	if (samples != last_samples &&
 1284: 	    ((samples != (last_samples-1)) || samples < 3)) {
 1285: 		msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
 1286: 			samples, last_samples, samplereduce);
 1287: 		last_samples = samples;
 1288: 	}
 1289: 	if (samples < 1) return;
 1290: 
 1291: 	/* If requested, dump the raw data we have in the buffer */
 1292: 	if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw  data  is:");
 1293: 
 1294: 	/* Sort the offsets, trim off the extremes, then choose one. */
 1295: 	qsort(
 1296: #ifdef QSORT_USES_VOID_P
 1297: 	    (void *)
 1298: #else
 1299: 	    (char *)
 1300: #endif
 1301: 	    coffs, (size_t)samples, sizeof(l_fp), offcompare);
 1302: 
 1303: 	noff = samples;
 1304: 	i = 0;
 1305: 	while ((noff - i) > samplereduce) {
 1306: 		/* Trim off the sample which is further away
 1307: 		 * from the median.  We work this out by doubling
 1308: 		 * the median, subtracting off the end samples, and
 1309: 		 * looking at the sign of the answer, using the
 1310: 		 * identity (c-b)-(b-a) == 2*b-a-c
 1311: 		 */
 1312: 		tmp = coffs[(noff + i)/2];
 1313: 		L_ADD(&tmp, &tmp);
 1314: 		L_SUB(&tmp, &coffs[i]);
 1315: 		L_SUB(&tmp, &coffs[noff-1]);
 1316: 		if (L_ISNEG(&tmp)) noff--; else i++;
 1317: 	}
 1318: 
 1319: 	/* If requested, dump the reduce data we have in the buffer */
 1320: 	if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced    to:");
 1321: 
 1322: 	/* What we do next depends on the setting of the sloppy clock flag.
 1323: 	 * If it is on, average the remainder to derive our estimate.
 1324: 	 * Otherwise, just pick a representative value from the remaining stuff
 1325: 	 */
 1326: 	if (sloppyclockflag[ees->unit]) {
 1327: 		offset.l_ui = offset.l_uf = 0;
 1328: 		for (j = i; j < noff; j++)
 1329: 		    L_ADD(&offset, &coffs[j]);
 1330: 		for (j = samplelog; j > 0; j--)
 1331: 		    L_RSHIFTU(&offset);
 1332: 	}
 1333: 	else offset = coffs[i+BESTSAMPLE];
 1334: 
 1335: 	/* Compute the dispersion as the difference between the
 1336: 	 * lowest and highest offsets that remain in the
 1337: 	 * consideration list.
 1338: 	 *
 1339: 	 * It looks like MOST clocks have MOD (max error), so halve it !
 1340: 	 */
 1341: 	tmp = coffs[noff-1];
 1342: 	L_SUB(&tmp, &coffs[i]);
 1343: #define	FRACT_SEC(n) ((1 << 30) / (n/2))
 1344: 	dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
 1345: 	if (dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog(
 1346: 		(dbg & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
 1347: 		"I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d",
 1348: 		dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
 1349: 		offset.l_f / 4295, offset.l_f,
 1350: 		(dispersion * 1526) / 100,
 1351: 		(sloppyclockflag[ees->unit]) ? " by averaging" : "",
 1352: 		FRACT_SEC(10) / 4295,
 1353: 		(coffs[0].l_f) / 4295,
 1354: 		i,
 1355: 		(coffs[i].l_f) / 4295,
 1356: 		(coffs[samples/2].l_f) / 4295,
 1357: 		(coffs[i+BESTSAMPLE].l_f) / 4295,
 1358: 		noff-1,
 1359: 		(coffs[noff-1].l_f) / 4295,
 1360: 		(coffs[samples-1].l_f) / 4295);
 1361: 
 1362: 	/* Are we playing silly wotsits ?
 1363: 	 * If we are using all data, see if there is a "small" delta,
 1364: 	 * and if so, blurr this with 3/4 of the delta from the last value
 1365: 	 */
 1366: 	if (ees->usealldata && ees->offset.l_uf) {
 1367: 		long diff = (long) (ees->offset.l_uf - offset.l_uf);
 1368: 
 1369: 		/* is the delta small enough ? */
 1370: 		if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
 1371: 			int samd = (64 * 4) / samples;
 1372: 			long new;
 1373: 			if (samd < 2) samd = 2;
 1374: 			new = offset.l_uf + ((diff * (samd -1)) / samd);
 1375: 
 1376: 			/* Sign change -> need to fix up int part */
 1377: 			if ((new & 0x80000000) !=
 1378: 			    (((long) offset.l_uf) & 0x80000000))
 1379: 			{	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
 1380: 					msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), so add %d",
 1381: 						new & 0x80000000,
 1382: 						((long) offset.l_uf) & 0x80000000,
 1383: 						new, (long) offset.l_uf,
 1384: 						(new < 0) ? -1 : 1);
 1385: 				offset.l_ui += (new < 0) ? -1 : 1;
 1386: 			}
 1387: 			dispersion /= 4;
 1388: 			if (dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) msyslog(
 1389: 				(dbg & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
 1390: 				"I: [%x] Smooth data: %ld -> %ld, dispersion now %f",
 1391: 				dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
 1392: 				((long) offset.l_uf) / 4295, new / 4295,
 1393: 				(dispersion * 1526) / 100);
 1394: 			offset.l_uf = (unsigned long) new;
 1395: 		}
 1396: 		else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
 1397: 			(dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
 1398: 			"[%x] No smooth as delta not %d < %ld < %d",
 1399: 			dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
 1400: 			- FRACT_SEC(100), diff, FRACT_SEC(100));
 1401: 	}
 1402: 	else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
 1403: 		(dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
 1404: 		"I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
 1405: 		dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
 1406: 		ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
 1407: 		offset.l_f, ees->offset.l_f - offset.l_f);
 1408: 
 1409: 	/* Collect offset info for debugging info */
 1410: 	ees->offset = offset;
 1411: 	ees->lowoffset = coffs[i];
 1412: 	ees->highoffset = coffs[noff-1];
 1413: 
 1414: 	/* Determine synchronization status.  Can be unsync'd either
 1415: 	 * by a report from the clock or by a leap hold.
 1416: 	 *
 1417: 	 * Loss of the radio signal for a short time does not cause
 1418: 	 * us to go unsynchronised, since the receiver keeps quite
 1419: 	 * good time on its own.  The spec says 20ms in 4 hours; the
 1420: 	 * observed drift in our clock (Cambridge) is about a second
 1421: 	 * a day, but even that keeps us within the inherent tolerance
 1422: 	 * of the clock for about 15 minutes. Observation shows that
 1423: 	 * the typical "short" outage is 3 minutes, so to allow us
 1424: 	 * to ride out those, we will give it 5 minutes.
 1425: 	 */
 1426: 	lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
 1427: 	isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
 1428: 
 1429: 	/* Done.  Use time of last good, synchronised code as the
 1430: 	 * reference time, and lastsampletime as the receive time.
 1431: 	 */
 1432: 	if (ees->fix_pending) {
 1433: 		msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
 1434: 			ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
 1435: 		ees->fix_pending = 0;
 1436: 	}
 1437: 	LFPTOD(&offset, doffset);
 1438: 	refclock_receive(ees->peer);
 1439: 	ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
 1440: }
 1441: 
 1442: /* msfees_poll - called by the transmit procedure */
 1443: static void
 1444: msfees_poll(
 1445: 	int unit,
 1446: 	struct peer *peer
 1447: 	)
 1448: {
 1449: 	if (unit >= MAXUNITS) {
 1450: 		msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
 1451: 			unit);
 1452: 		return;
 1453: 	}
 1454: 	if (!unitinuse[unit]) {
 1455: 		msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
 1456: 			unit);
 1457: 		return;
 1458: 	}
 1459: 
 1460: 	ees_process(eesunits[unit]);
 1461: 
 1462: 	if ((current_time - eesunits[unit]->lasttime) > 150)
 1463: 	    ees_event(eesunits[unit], CEVNT_FAULT);
 1464: }
 1465: 
 1466: 
 1467: #else
 1468: int refclock_msfees_bs;
 1469: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>