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