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