#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <sys/time.h>
#ifdef HAVE_TIMEX_H
# include "timex.h"
#endif
#define HZ 100
#define MAXPHASE 512000
#define MAXFREQ 200
#define TAU 2
#define POLL 16
#define MAXSEC 1200
void hardupdate();
void hardclock();
void second_overflow();
int tick;
int fixtick;
struct timeval timex;
int time_status = TIME_BAD;
long time_offset = 0;
long time_constant = 0;
long time_tolerance = MAXFREQ;
long time_precision = 1000000 / HZ;
long time_maxerror = MAXPHASE;
long time_esterror = MAXPHASE;
long time_phase = 0;
long time_freq = 0;
long time_adj = 0;
long time_reftime = 0;
double timey = 0;
long timez = 0;
long poll_interval = 0;
int
main(
int argc,
char *argv[]
)
{
tick = 1000000 / HZ;
fixtick = 1000000 % HZ;
timex.tv_sec = 0;
timex.tv_usec = MAXPHASE;
time_freq = 0;
time_constant = TAU;
printf("tick %d us, fixtick %d us\n", tick, fixtick);
printf(" time offset freq _offset _freq _adj\n");
while (1) {
timey += (double)(1000000) / HZ;
if (timey >= 1000000)
timey -= 1000000;
hardclock();
if (timex.tv_usec >= 1000000) {
timex.tv_usec -= 1000000;
timex.tv_sec++;
second_overflow();
poll_interval++;
if (!(poll_interval % POLL)) {
timez = (long)timey - timex.tv_usec;
if (timez > 500000)
timez -= 1000000;
if (timez < -500000)
timez += 1000000;
hardupdate(timez);
printf("%10li%10li%10.2f %08lx %08lx %08lx\n",
timex.tv_sec, timez,
(double)time_freq / (1 << SHIFT_KF),
time_offset, time_freq, time_adj);
}
}
}
}
void
hardupdate(
long offset
)
{
long ltemp, mtemp;
time_offset = offset << SHIFT_UPDATE;
mtemp = timex.tv_sec - time_reftime;
time_reftime = timex.tv_sec;
if (mtemp > MAXSEC)
mtemp = 0;
if (offset < 0)
time_freq -= (-offset * mtemp) >>
(time_constant + time_constant);
else
time_freq += (offset * mtemp) >>
(time_constant + time_constant);
ltemp = time_tolerance << SHIFT_KF;
if (time_freq > ltemp)
time_freq = ltemp;
else if (time_freq < -ltemp)
time_freq = -ltemp;
if (time_status == TIME_BAD)
time_status = TIME_OK;
}
void
hardclock(void)
{
int ltemp, time_update;
time_update = tick;
time_phase += time_adj;
if (time_phase < -FINEUSEC) {
ltemp = -time_phase >> SHIFT_SCALE;
time_phase += ltemp << SHIFT_SCALE;
time_update -= ltemp;
}
else if (time_phase > FINEUSEC) {
ltemp = time_phase >> SHIFT_SCALE;
time_phase -= ltemp << SHIFT_SCALE;
time_update += ltemp;
}
timex.tv_usec += time_update;
}
void
second_overflow(void)
{
int ltemp;
time_maxerror += time_tolerance;
if (time_offset < 0) {
ltemp = -time_offset >>
(SHIFT_KG + time_constant);
time_offset += ltemp;
time_adj = -(ltemp <<
(SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE));
} else {
ltemp = time_offset >>
(SHIFT_KG + time_constant);
time_offset -= ltemp;
time_adj = ltemp <<
(SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
}
if (time_freq < 0)
time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
else
time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE);
time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ);
if (timex.tv_sec % 86400 == 0) {
switch (time_status) {
case TIME_INS:
timex.tv_sec--;
time_status = TIME_OOP;
break;
case TIME_DEL:
timex.tv_sec++;
time_status = TIME_OK;
break;
case TIME_OOP:
time_status = TIME_OK;
break;
}
}
}