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 } 226