Annotation of embedaddon/ntp/util/kern.c, revision 1.1
1.1 ! misho 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>