File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / util / kern.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, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * This program simulates a first-order, type-II phase-lock loop using
    3:  * actual code segments from modified kernel distributions for SunOS,
    4:  * Ultrix and OSF/1 kernels. These segments do not use any licensed code.
    5:  */
    6: 
    7: #ifdef HAVE_CONFIG_H
    8: # include <config.h>
    9: #endif
   10: 
   11: #include <stdio.h>
   12: #include <ctype.h>
   13: #include <math.h>
   14: #include <sys/time.h>
   15: 
   16: #ifdef HAVE_TIMEX_H
   17: # include "timex.h"
   18: #endif
   19: 
   20: /*
   21:  * Phase-lock loop definitions
   22:  */
   23: #define HZ 100			/* timer interrupt frequency (Hz) */
   24: #define MAXPHASE 512000		/* max phase error (us) */
   25: #define MAXFREQ 200		/* max frequency error (ppm) */
   26: #define TAU 2			/* time constant (shift 0 - 6) */
   27: #define POLL 16			/* interval between updates (s) */
   28: #define MAXSEC 1200		/* max interval between updates (s) */
   29: 
   30: /*
   31:  * Function declarations
   32:  */
   33: void hardupdate();
   34: void hardclock();
   35: void second_overflow();
   36: 
   37: /*
   38:  * Kernel variables
   39:  */
   40: int tick;			/* timer interrupt period (us) */
   41: int fixtick;			/* amortization constant (ppm) */
   42: struct timeval timex;		/* ripoff of kernel time variable */
   43: 
   44: /*
   45:  * Phase-lock loop variables
   46:  */
   47: int time_status = TIME_BAD;	/* clock synchronization status */
   48: long time_offset = 0;		/* time adjustment (us) */
   49: long time_constant = 0;		/* pll time constant */
   50: long time_tolerance = MAXFREQ;	/* frequency tolerance (ppm) */
   51: long time_precision = 1000000 / HZ; /* clock precision (us) */
   52: long time_maxerror = MAXPHASE;	/* maximum error (us) */
   53: long time_esterror = MAXPHASE;	/* estimated error (us) */
   54: long time_phase = 0;		/* phase offset (scaled us) */
   55: long time_freq = 0;		/* frequency offset (scaled ppm) */
   56: long time_adj = 0;		/* tick adjust (scaled 1 / HZ) */
   57: long time_reftime = 0;		/* time at last adjustment (s) */
   58: 
   59: /*
   60:  * Simulation variables
   61:  */
   62: double timey = 0;		/* simulation time (us) */
   63: long timez = 0;			/* current error (us) */
   64: long poll_interval = 0;		/* poll counter */
   65: 
   66: /*
   67:  * Simulation test program
   68:  */
   69: int
   70: main(
   71: 	int argc,
   72: 	char *argv[]
   73: 	)
   74: {
   75: 	tick = 1000000 / HZ;
   76: 	fixtick = 1000000 % HZ;
   77: 	timex.tv_sec = 0;
   78: 	timex.tv_usec = MAXPHASE;
   79: 	time_freq = 0;
   80: 	time_constant = TAU;
   81: 	printf("tick %d us, fixtick %d us\n", tick, fixtick);
   82: 	printf("      time    offset      freq   _offset     _freq      _adj\n");
   83: 
   84: 	/*
   85: 	 * Grind the loop until ^C
   86: 	 */
   87: 	while (1) {
   88: 		timey += (double)(1000000) / HZ;
   89: 		if (timey >= 1000000)
   90: 		    timey -= 1000000;
   91: 		hardclock();
   92: 		if (timex.tv_usec >= 1000000) {
   93: 			timex.tv_usec -= 1000000;
   94: 			timex.tv_sec++;
   95: 			second_overflow();
   96: 			poll_interval++;
   97: 			if (!(poll_interval % POLL)) {
   98: 				timez = (long)timey - timex.tv_usec;
   99: 				if (timez > 500000)
  100: 				    timez -= 1000000;
  101: 				if (timez < -500000)
  102: 				    timez += 1000000;
  103: 				hardupdate(timez);
  104: 				printf("%10li%10li%10.2f  %08lx  %08lx  %08lx\n",
  105: 				       timex.tv_sec, timez,
  106: 				       (double)time_freq / (1 << SHIFT_KF),
  107: 				       time_offset, time_freq, time_adj);
  108: 			}
  109: 		}
  110: 	}
  111: }
  112: 
  113: /*
  114:  * This routine simulates the ntp_adjtime() call
  115:  *
  116:  * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the
  117:  * maximum interval between updates is 4096 s and the maximum frequency
  118:  * offset is +-31.25 ms/s.
  119:  */
  120: void
  121: hardupdate(
  122: 	long offset
  123: 	)
  124: {
  125: 	long ltemp, mtemp;
  126: 
  127: 	time_offset = offset << SHIFT_UPDATE;
  128: 	mtemp = timex.tv_sec - time_reftime;
  129: 	time_reftime = timex.tv_sec;
  130: 	if (mtemp > MAXSEC)
  131: 	    mtemp = 0;
  132: 
  133: 	/* ugly multiply should be replaced */
  134: 	if (offset < 0)
  135: 	    time_freq -= (-offset * mtemp) >>
  136: 		    (time_constant + time_constant);
  137: 	else
  138: 	    time_freq += (offset * mtemp) >>
  139: 		    (time_constant + time_constant);
  140: 	ltemp = time_tolerance << SHIFT_KF;
  141: 	if (time_freq > ltemp)
  142: 	    time_freq = ltemp;
  143: 	else if (time_freq < -ltemp)
  144: 	    time_freq = -ltemp;
  145: 	if (time_status == TIME_BAD)
  146: 	    time_status = TIME_OK;
  147: }
  148: 
  149: /*
  150:  * This routine simulates the timer interrupt
  151:  */
  152: void
  153: hardclock(void)
  154: {
  155: 	int ltemp, time_update;
  156: 
  157: 	time_update = tick;	/* computed by adjtime() */
  158: 	time_phase += time_adj;
  159: 	if (time_phase < -FINEUSEC) {
  160: 		ltemp = -time_phase >> SHIFT_SCALE;
  161: 		time_phase += ltemp << SHIFT_SCALE;
  162: 		time_update -= ltemp;
  163: 	}
  164: 	else if (time_phase > FINEUSEC) {
  165: 		ltemp = time_phase >> SHIFT_SCALE;
  166: 		time_phase -= ltemp << SHIFT_SCALE;
  167: 		time_update += ltemp;
  168: 	}
  169: 	timex.tv_usec += time_update;
  170: }
  171: 
  172: /*
  173:  * This routine simulates the overflow of the microsecond field
  174:  *
  175:  * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us
  176:  * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time
  177:  * contribution is shifted right a minimum of two bits, while the frequency
  178:  * contribution is a right shift. Thus, overflow is prevented if the
  179:  * frequency contribution is limited to half the maximum or 15.625 ms/s.
  180:  */
  181: void
  182: second_overflow(void)
  183: {
  184: 	int ltemp;
  185: 
  186: 	time_maxerror += time_tolerance;
  187: 	if (time_offset < 0) {
  188: 		ltemp = -time_offset >>
  189: 			(SHIFT_KG + time_constant);
  190: 		time_offset += ltemp;
  191: 		time_adj = -(ltemp <<
  192: 			     (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE));
  193: 	} else {
  194: 		ltemp = time_offset >>
  195: 			(SHIFT_KG + time_constant);
  196: 		time_offset -= ltemp;
  197: 		time_adj = ltemp <<
  198: 			(SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
  199: 	}
  200: 	if (time_freq < 0)
  201: 	    time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
  202: 	else
  203: 	    time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
  204: 	time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ);
  205: 
  206: 	/* ugly divide should be replaced */
  207: 	if (timex.tv_sec % 86400 == 0) {
  208: 		switch (time_status) {
  209: 
  210: 		    case TIME_INS:
  211: 			timex.tv_sec--; /* !! */
  212: 			time_status = TIME_OOP;
  213: 			break;
  214: 
  215: 		    case TIME_DEL:
  216: 			timex.tv_sec++;
  217: 			time_status = TIME_OK;
  218: 			break;
  219: 
  220: 		    case TIME_OOP:
  221: 			time_status = TIME_OK;
  222: 			break;
  223: 		}
  224: 	}
  225: }

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