ntpclient.c修改了官方文件:
/*
* ntpclient.c - NTP client
*
* Copyright 1997, 1999, 2000 Larry Doolittle
* Last hack: 2 December, 2000
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (Version 2,
* June 1991) as published by the Free Software Foundation. At the
* time of writing, that license was published by the FSF with the URL
* http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
* reference.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Possible future improvements:
* - Double check that the originate timestamp in the received packet
* corresponds to what we sent.
* - Verify that the return packet came from the host we think
* we're talking to. Not necessarily useful since UDP packets
* are so easy to forge.
* - Complete phase locking code.
* - Write more documentation :-(
*
* Compile with -D_PRECISION_SIOCGSTAMP if your machine really has it.
* There are patches floating around to add this to Linux, but
* usually you only get an answer to the nearest jiffy.
* Hint for Linux hacker wannabes: look at the usage of get_fast_time()
* in net/core/dev.c, and its definition in kernel/time.c .
*
* If the compile gives you any flak, check below in the section
* labelled "XXXX fixme - non-automatic build configuration".
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef _PRECISION_SIOCGSTAMP
#include
#endif
#define ENABLE_DEBUG
extern char *optarg;
/* XXXX fixme - non-automatic build configuration */
#ifdef linux
typedef u_int32_t __u32;
#include
#else
extern int h_errno;
#define herror(hostname) \
fprintf(stderr,"Error %d looking up hostname %s\n", h_errno,hostname)
typedef uint32_t __u32;
#endif
#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */
#define NTP_PORT (123)
/* How to multiply by 4294.967296 quickly (and not quite exactly)
* without using floating point or greater than 32-bit integers.
* If you want to fix the last 12 microseconds of error, add in
* (2911*(x))>>28)
*/
#define NTPFRAC(x) ( 4294*(x) + ( (1981*(x))>>11 ) )
/* The reverse of the above, needed if we want to set our microsecond
* clock (via settimeofday) based on the incoming time in NTP format.
* Basically exact.
*/
#define USEC(x) ( ( (x) >> 12 ) - 759 * ( ( ( (x) >> 10 ) + 32768 ) >> 16 ) )
/* Converts NTP delay and dispersion, apparently in seconds scaled
* by 65536, to microseconds. RFC1305 states this time is in seconds,
* doesn't mention the scaling.
* Should somehow be the same as 1000000 * x / 65536
*/
#define sec2u(x) ( (x) * 15.2587890625 )
struct ntptime {
unsigned int coarse;
unsigned int fine;
};
void send_packet(int usd);
void rfc1305print(char *data, struct ntptime *arrival);
void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len);
/* global variables (I know, bad form, but this is a short program) */
char incoming[1500];
struct timeval time_of_send;
int live=0;
int set_clock=1; /* non-zero presumably needs root privs */
#ifdef ENABLE_DEBUG
int debug=0;
#define DEBUG_OPTION "d"
#else
#define debug 0
#define DEBUG_OPTION
#endif
int contemplate_data(unsigned int absolute, double skew, double errorbar, int freq);
int get_current_freq()
{
/* OS dependent routine to get the current value of clock frequency.
*/
#ifdef linux
struct timex txc;
txc.modes=0;
if (__adjtimex(&txc) < 0) {
perror("adjtimex"); exit(1);
}
return txc.freq;
#else
return 0;
#endif
}
int set_freq(int new_freq)
{
/* OS dependent routine to set a new value of clock frequency.
*/
#ifdef linux
struct timex txc;
txc.modes = ADJ_FREQUENCY;
txc.freq = new_freq;
if (__adjtimex(&txc) < 0) {
perror("adjtimex"); exit(1);
}
return txc.freq;
#else
return 0;
#endif
}
void send_packet(int usd)
{
__u32 data[12];
struct timeval now;
#define LI 0
#define VN 3
#define MODE 3
#define STRATUM 0
#define POLL 4
#define PREC -6
if (debug) fprintf(stderr,"Sending ...\n");
if (sizeof(data) != 48) {
fprintf(stderr,"size error\n");
return;
}
bzero(data,sizeof(data));
data[0] = htonl (
( LI << 30 ) | ( VN << 27 ) | ( MODE << 24 ) |
( STRATUM << 16) | ( POLL << 8 ) | ( PREC & 0xff ) );
data[1] = htonl(1<<16); /* Root Delay (seconds) */
data[2] = htonl(1<<16); /* Root Dispersion (seconds) */
gettimeofday(&now,NULL);
data[10] = htonl(now.tv_sec + JAN_1970); /* Transmit Timestamp coarse */
data[11] = htonl(NTPFRAC(now.tv_usec)); /* Transmit Timestamp fine */
send(usd,data,48,0);
time_of_send=now;
}
void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len)
{
struct timeval udp_arrival;
struct ntptime udp_arrival_ntp;
#ifdef _PRECISION_SIOCGSTAMP
if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) {
perror("ioctl-SIOCGSTAMP");
gettimeofday(&udp_arrival,NULL);
}
#else
gettimeofday(&udp_arrival,NULL);
#endif
udp_arrival_ntp.coarse = udp_arrival.tv_sec + JAN_1970;
udp_arrival_ntp.fine = NTPFRAC(udp_arrival.tv_usec);
if (debug) {
struct sockaddr_in *sa_in=(struct sockaddr_in *)sa_source;
printf("packet of length %d received\n",data_len);
if (sa_source->sa_family==AF_INET) {
printf("Source: INET Port %d host %s\n",
ntohs(sa_in->sin_port),inet_ntoa(sa_in->sin_addr));
} else {
printf("Source: Address family %d\n",sa_source->sa_family);
}
}
rfc1305print(data,&udp_arrival_ntp);
}
double ntpdiff( struct ntptime *start, struct ntptime *stop)
{
int a;
unsigned int b;
a = stop->coarse - start->coarse;
if (stop->fine >= start->fine) {
b = stop->fine - start->fine;
} else {
b = start->fine - stop->fine;
b = ~b;
a -= 1;
}
return a*1.e6 + b * (1.e6/4294967296.0);
}
void unpack_ntp_data(char *data)
{
long long transmit_time;
struct tm *localtm;
memcpy(&transmit_time, data + 32, 4);
transmit_time = ntohl(transmit_time) - JAN_1970;
printf("transmit time : %llx\n", transmit_time);
//time(&time_tmp);
localtm= gmtime(&transmit_time);
printf("Year : %d month : %d dat : %d h : %d m : %d s:%d\n",
localtm->tm_year + 1900,
localtm->tm_mon + 1,
localtm->tm_mday,
localtm->tm_hour + 8,
localtm->tm_min,
localtm->tm_sec);
}
/* Does more than print, so this name is bogus.
* It also makes time adjustments, both sudden (-s)
* and phase-locking (-l). */
void rfc1305print(char *data, struct ntptime *arrival)
{
unpack_ntp_data(data);
/* straight out of RFC-1305 Appendix A */
int li, vn, mode, stratum, poll, prec;
int delay, disp, refid;
struct ntptime reftime, orgtime, rectime, xmttime;
double etime,stime,skew1,skew2;
int freq;
#define Data(i) ntohl(((unsigned int *)data)[i])
li = Data(0) >> 30 & 0x03;
vn = Data(0) >> 27 & 0x07;
mode = Data(0) >> 24 & 0x07;
stratum = Data(0) >> 16 & 0xff;
poll = Data(0) >> 8 & 0xff;
prec = Data(0) & 0xff;
if (prec & 0x80) prec|=0xffffff00;
delay = Data(1);
disp = Data(2);
refid = Data(3);
reftime.coarse = Data(4);
reftime.fine = Data(5);
orgtime.coarse = Data(6);
orgtime.fine = Data(7);
rectime.coarse = Data(8);
rectime.fine = Data(9);
xmttime.coarse = Data(10);
xmttime.fine = Data(11);
#undef Data
if (set_clock) { /* you'd better be root, or ntpclient will crash! */
struct timeval tv_set;
/* it would be even better to subtract half the slop */
tv_set.tv_sec = xmttime.coarse - JAN_1970;
/* divide xmttime.fine by 4294.967296 */
tv_set.tv_usec = USEC(xmttime.fine);
if (settimeofday(&tv_set,NULL)<0) {
perror("settimeofday");
exit(1);
}
if (debug) {
printf("set time to %lu.%.6lu\n", tv_set.tv_sec, tv_set.tv_usec);
}
}
if (debug) {
printf("LI=%d VN=%d Mode=%d Stratum=%d Poll=%d Precision=%d\n",
li, vn, mode, stratum, poll, prec);
printf("Delay=%.1f Dispersion=%.1f Refid=%u.%u.%u.%u\n",
sec2u(delay),sec2u(disp),
refid>>24&0xff, refid>>16&0xff, refid>>8&0xff, refid&0xff);
printf("Reference %u.%.10u\n", reftime.coarse, reftime.fine);
printf("Originate %u.%.10u\n", orgtime.coarse, orgtime.fine);
printf("Receive %u.%.10u\n", rectime.coarse, rectime.fine);
printf("Transmit %u.%.10u\n", xmttime.coarse, xmttime.fine);
printf("Our recv %u.%.10u\n", arrival->coarse, arrival->fine);
}
etime=ntpdiff(&orgtime,arrival);
stime=ntpdiff(&rectime,&xmttime);
skew1=ntpdiff(&orgtime,&rectime);
skew2=ntpdiff(&xmttime,arrival);
freq=get_current_freq();
if (debug) {
printf("Total elapsed: %9.2f\n"
"Server stall: %9.2f\n"
"Slop: %9.2f\n",
etime, stime, etime-stime);
printf("Skew: %9.2f\n"
"Frequency: %9d\n"
" day second elapsed stall skew dispersion freq\n",
(skew1-skew2)/2, freq);
}
/* Not the ideal order for printing, but we want to be sure
* to do all the time-sensitive thinking (and time setting)
* before we start the output, especially fflush() (which
* could be slow). Of course, if debug is turned on, speed
* has gone down the drain anyway. */
if (live) {
int new_freq;
new_freq = contemplate_data(arrival->coarse, (skew1-skew2)/2,
etime+sec2u(disp), freq);
if (!debug && new_freq != freq) set_freq(new_freq);
}
printf("%d %5d.%.3d %8.1f %8.1f %8.1f %8.1f %9d\n",
arrival->coarse/86400+15020, arrival->coarse%86400,
arrival->fine/4294967, etime, stime,
(skew1-skew2)/2, sec2u(disp), freq);
fflush(stdout);
}
void stuff_net_addr(struct in_addr *p, char *hostname)
{
struct hostent *ntpserver;
ntpserver=gethostbyname(hostname);
if (ntpserver == NULL) {
herror(hostname);
exit(1);
}
if (ntpserver->h_length != 4) {
fprintf(stderr,"oops %d\n",ntpserver->h_length);
exit(1);
}
memcpy(&(p->s_addr),ntpserver->h_addr_list[0],4);
}
void setup_receive(int usd, unsigned int interface, short port)
{
struct sockaddr_in sa_rcvr;
bzero((char *) &sa_rcvr, sizeof(sa_rcvr));
sa_rcvr.sin_family=AF_INET;
sa_rcvr.sin_addr.s_addr=htonl(interface);
sa_rcvr.sin_port=htons(port);
if(bind(usd,(struct sockaddr *) &sa_rcvr,sizeof(sa_rcvr)) == -1) {
fprintf(stderr,"could not bind to udp port %d\n",port);
perror("bind");
exit(1);
}
listen(usd,3);
}
void setup_transmit(int usd, char *host, short port)
{
struct sockaddr_in sa_dest;
bzero((char *) &sa_dest, sizeof(sa_dest));
sa_dest.sin_family=AF_INET;
stuff_net_addr(&(sa_dest.sin_addr),host);
sa_dest.sin_port=htons(port);
if (connect(usd,(struct sockaddr *)&sa_dest,sizeof(sa_dest))==-1)
{perror("connect");exit(1);}
}
void primary_loop(int usd, int num_probes, int interval)
{
fd_set fds;
struct sockaddr sa_xmit;
int i, pack_len, sa_xmit_len, probes_sent;
struct timeval to;
if (debug) printf("Listening...\n");
probes_sent=0;
sa_xmit_len=sizeof(sa_xmit);
to.tv_sec=0;
to.tv_usec=0;
for (;;) {
FD_ZERO(&fds);
FD_SET(usd,&fds);
i=select(usd+1,&fds,NULL,NULL,&to); /* Wait on read or error */
if ((i!=1)||(!FD_ISSET(usd,&fds))) {
if (i==EINTR) continue;
if (i<0) perror("select");
if (to.tv_sec == 0) {
if (probes_sent >= num_probes &&
num_probes != 0) break;
send_packet(usd);
++probes_sent;
to.tv_sec=interval;
to.tv_usec=0;
}
continue;
}
pack_len=recvfrom(usd,incoming,sizeof(incoming),0,
&sa_xmit,&sa_xmit_len);
if (pack_len<0) {
perror("recvfrom");
} else if (pack_len>0 && pack_len<sizeof(incoming)){
udp_handle(usd,incoming,pack_len,&sa_xmit,sa_xmit_len);
} else {
printf("Ooops. pack_len=%d\n",pack_len);
fflush(stdout);
}
if (probes_sent >= num_probes && num_probes != 0) break;
}
}
void do_replay(void)
{
char line[100];
int n, day, freq, absolute;
float sec, etime, stime, disp;
double skew, errorbar;
int simulated_freq = 0;
unsigned int last_fake_time = 0;
double fake_delta_time = 0.0;
while (fgets(line,sizeof(line),stdin)) {
n=sscanf(line,"%d %f %f %f %lf %f %d",
&day, &sec, &etime, &stime, &skew, &disp, &freq);
if (n==7) {
fputs(line,stdout);
absolute=(day-15020)*86400+(int)sec;
errorbar=etime+disp;
if (debug) printf("contemplate %u %.1f %.1f %d\n",
absolute,skew,errorbar,freq);
if (last_fake_time==0) simulated_freq=freq;
fake_delta_time += (absolute-last_fake_time)*((double)(freq-simulated_freq))/65536;
if (debug) printf("fake %f %d \n", fake_delta_time, simulated_freq);
skew += fake_delta_time;
freq = simulated_freq;
last_fake_time=absolute;
simulated_freq = contemplate_data(absolute, skew, errorbar, freq);
} else {
fprintf(stderr,"Replay input error\n");
exit(2);
}
}
}
void usage(char *argv0)
{
fprintf(stderr,
"Usage: %s [-c count] [-d] -h hostname [-i interval] [-l]\n"
"\t[-p port] [-r] [-s] \n",
argv0);
}
int main(int argc, char *argv[]) {
int usd;
int c;
short int udp_local_port=0;
int cycle_time=600;
int probe_count=1;
char *hostname="time.nist.gov";;
int replay=0;
if ((usd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1)
{perror ("socket");exit(1);}
setup_receive(usd, INADDR_ANY, udp_local_port);
setup_transmit(usd, hostname, NTP_PORT);
primary_loop(usd, probe_count, cycle_time);
close(usd);
return 0;
}
phaselock.c
/*
* phaselock.c - Phase locking for NTP client
*
* Copyright 2000 Larry Doolittle
* Last hack: 28 November, 2000
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (Version 2,
* June 1991) as published by the Free Software Foundation. At the
* time of writing, that license was published by the FSF with the URL
* http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
* reference.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Possible future improvements:
* - Subtract configurable amount from errorbar
* - Build in general run-time access to tune parameters
* - Sculpt code so it's legible, this version is out of control
* - Write documentation :-(
*/
#include
#define ENABLE_DEBUG
#define RING_SIZE 16
struct datum {
unsigned int absolute;
double skew;
double errorbar;
int freq;
/* s.s.min and s.s.max (skews) are "corrected" to what they would
* have been if freq had been constant at its current value during
* the measurements.
*/
union {
struct { double min; double max; } s;
double ss[2];
} s;
/*
double smin;
double smax;
*/
} d_ring[RING_SIZE];
struct _seg {
double slope;
double offset;
} maxseg[RING_SIZE+1], minseg[RING_SIZE+1];
#ifdef ENABLE_DEBUG
extern int debug;
#define DEBUG_OPTION "d"
#else
#define debug 0
#define DEBUG_OPTION
#endif
/* draw a line from a to c, what the offset is of that line
* where that line matches b's slope coordinate.
*/
double interpolate(struct _seg *a, struct _seg *b, struct _seg *c)
{
double x, y;
x = (b->slope - a->slope) / (c->slope - a->slope) ;
y = a->offset + x * (c->offset - a->offset);
return y;
}
int next_up(int i) { int r = i+1; if (r>=RING_SIZE) r=0; return r;}
int next_dn(int i) { int r = i-1; if (r<0) r=RING_SIZE-1; return r;}
/* Looks at the line segments that start at point j, that end at
* all following points (ending at index rp). The initial point
* is on curve s0, the ending point is on curve s1. The curve choice
* (s.min vs. s.max) is based on the index in ss[]. The scan
* looks for the largest (sign=0) or smallest (sign=1) slope.
*/
int search(int rp, int j, int s0, int s1, int sign, struct _seg *answer)
{
double dt, slope;
int n, nextj=0, cinit=1;
for (n=next_up(j); n!=next_up(rp); n=next_up(n)) {
if (0 && debug) printf("d_ring[%d].s.ss[%d]=%f d_ring[%d].s.ss[%d]=%f\n",
n, s0, d_ring[n].s.ss[s0], j, s1, d_ring[j].s.ss[s1]);
dt = d_ring[n].absolute - d_ring[j].absolute;
slope = (d_ring[n].s.ss[s0] - d_ring[j].s.ss[s1]) / dt;
if (0 && debug) printf("slope %d%d%d [%d,%d] = %f\n",
s0, s1, sign, j, n, slope);
if (cinit || (slope < answer->slope) ^ sign) {
answer->slope = slope;
answer->offset = d_ring[n].s.ss[s0] +
slope*(d_ring[rp].absolute - d_ring[n].absolute);
cinit = 0;
nextj = n;
}
}
return nextj;
}
/* Pseudo-class for finding consistent frequency shift */
#define MIN_INIT 20
struct _polygon {
double l_min;
double r_min;
} df;
void polygon_reset()
{
df.l_min = MIN_INIT;
df.r_min = MIN_INIT;
}
double find_df(int *flag)
{
if (df.l_min == 0.0) {
if (df.r_min == 0.0) {
return 0.0; /* every point was OK */
} else {
return -df.r_min;
}
} else {
if (df.r_min == 0.0) {
return df.l_min;
} else {
if (flag) *flag=1;
return 0.0; /* some points on each side,
* or no data at all */
}
}
}
/* Finds the amount of delta-f required to move a point onto a
* target line in delta-f/delta-t phase space. Any line is OK
* as long as it's not convex and never returns greater than
* MIN_INIT. */
double find_shift(double slope, double offset)
{
double shift = slope - offset/600.0;
double shift2 = slope + 0.3 - offset/6000.0;
if (shift2 < shift) shift = shift2;
if (debug) printf("find_shift %f %f -> %f\n", slope, offset, shift);
if (shift < 0) return 0.0;
return shift;
}
void polygon_point(struct _seg *s)
{
double l, r;
if (debug) printf("loop %f %f\n", s->slope, s->offset);
l = find_shift(- s->slope, s->offset);
r = find_shift( s->slope, - s->offset);
if (l < df.l_min) df.l_min = l;
if (r < df.r_min) df.r_min = r;
if (debug) printf("constraint left: %f %f \n", l, df.l_min);
if (debug) printf("constraint right: %f %f \n", r, df.r_min);
}
/* Something like linear feedback to be used when we are "close" to
* phase lock. Not really used at the moment: the logic in find_df()
* never sets the flag. */
double find_df_center(struct _seg *min, struct _seg *max, double gross_df)
{
const double crit_time=1000.0;
double slope = 0.5 * (max->slope + min->slope)+gross_df;
double dslope = (max->slope - min->slope);
double offset = 0.5 * (max->offset + min->offset);
double doffset = (max->offset - min->offset);
double delta1 = -offset/ 600.0 - slope;
double delta2 = -offset/1800.0 - slope;
double delta = 0.0;
double factor = crit_time/(crit_time+doffset+dslope*1200.0);
if (offset < 0 && delta2 > 0) delta = delta2;
if (offset < 0 && delta1 < 0) delta = delta1;
if (offset >= 0 && delta1 > 0) delta = delta1;
if (offset >= 0 && delta2 < 0) delta = delta2;
if (max->offset < -crit_time || min->offset > crit_time) return 0.0;
if (debug) printf("find_df_center %f %f\n", delta, factor);
return factor*delta;
}
int contemplate_data(unsigned int absolute, double skew, double errorbar, int freq)
{
/* Here is the actual phase lock loop.
* Need to keep a ring buffer of points to make a rational
* decision how to proceed. if (debug) print a lot.
*/
static int rp=0, valid=0;
int both_sides_now=0;
int j, n, c, max_avail, min_avail, dinit;
int nextj=0; /* initialization not needed; but gcc can't figure out my logic */
double cum;
struct _seg check, save_min, save_max;
double last_slope;
int delta_freq;
double delta_f;
int inconsistent=0, max_imax, max_imin=0, min_imax, min_imin=0;
int computed_freq=freq;
if (debug) printf("xontemplate %u %.1f %.1f %d\n",absolute,skew,errorbar,freq);
d_ring[rp].absolute = absolute;
d_ring[rp].skew = skew;
d_ring[rp].errorbar = errorbar - 800.0; /* quick hack to speed things up */
d_ring[rp].freq = freq;
if (validif (valid==RING_SIZE) {
/*
* Pass 1: correct for wandering freq's */
cum = 0.0;
if (debug) printf("\n");
for (j=rp; ; j=n) {
d_ring[j].s.s.max = d_ring[j].skew - cum + d_ring[j].errorbar;
d_ring[j].s.s.min = d_ring[j].skew - cum - d_ring[j].errorbar;
if (debug) printf("hist %d %d %f %f %f\n",j,d_ring[j].absolute-absolute,
cum,d_ring[j].s.s.min,d_ring[j].s.s.max);
n=next_dn(j);
if (n == rp) break;
/* Assume the freq change took place immediately after
* the data was taken; this is valid for the case where
* this program was responsible for the change.
*/
cum = cum + (d_ring[j].absolute-d_ring[n].absolute) *
(double)(d_ring[j].freq-freq)/65536;
}
/*
* Pass 2: find the convex down envelope of s.max, composed of
* line segments in s.max vs. absolute space, which are
* points in freq vs. dt space. Find points in order of increasing
* slope == freq */
dinit=1; last_slope=-100;
for (c=1, j=next_up(rp); ; j=nextj) {
nextj = search(rp, j, 1, 1, 0, &maxseg[c]);
search(rp, j, 0, 1, 1, &check);
if (check.slope < maxseg[c].slope && check.slope > last_slope &&
(dinit || check.slope < save_min.slope)) {dinit=0; save_min=check; }
if (debug) printf("maxseg[%d] = %f *x+ %f\n",
c, maxseg[c].slope, maxseg[c].offset);
last_slope = maxseg[c].slope;
c++;
if (nextj == rp) break;
}
if (dinit==1) inconsistent=1;
if (debug && dinit==0) printf ("mincross %f *x+ %f\n", save_min.slope, save_min.offset);
max_avail=c;
/*
* Pass 3: find the convex up envelope of s.min, composed of
* line segments in s.min vs. absolute space, which are
* points in freq vs. dt space. These points are found in
* order of decreasing slope. */
dinit=1; last_slope=+100.0;
for (c=1, j=next_up(rp); ; j=nextj) {
nextj = search(rp, j, 0, 0, 1, &minseg[c]);
search(rp, j, 1, 0, 0, &check);
if (check.slope > minseg[c].slope && check.slope < last_slope &&
(dinit || check.slope < save_max.slope)) {dinit=0; save_max=check; }
if (debug) printf("minseg[%d] = %f *x+ %f\n",
c, minseg[c].slope, minseg[c].offset);
last_slope = minseg[c].slope;
c++;
if (nextj == rp) break;
}
if (dinit==1) inconsistent=1;
if (debug && dinit==0) printf ("maxcross %f *x+ %f\n", save_max.slope, save_max.offset);
min_avail=c;
/*
* Pass 4: splice together the convex polygon that forms
* the envelope of slope/offset coordinates that are consistent
* with the observed data. The order of calls to polygon_point
* doesn't matter for the frequency shift determination, but
* the order chosen is nice for visual display. */
if (!inconsistent) {
polygon_reset();
polygon_point(&save_min);
for (dinit=1, c=1; cif (dinit && maxseg[c].slope > save_min.slope) {
max_imin = c-1;
maxseg[max_imin] = save_min;
dinit = 0;
}
if (maxseg[c].slope > save_max.slope)
break;
if (dinit==0) polygon_point(&maxseg[c]);
}
if (dinit && debug) printf("found maxseg vs. save_min inconsistency\n");
if (dinit) inconsistent=1;
max_imax = c;
maxseg[max_imax] = save_max;
polygon_point(&save_max);
for (dinit=1, c=1; cif (dinit && minseg[c].slope < save_max.slope) {
max_imin = c-1;
minseg[min_imin] = save_max;
dinit = 0;
}
if (minseg[c].slope < save_min.slope)
break;
if (dinit==0) polygon_point(&minseg[c]);
}
if (dinit && debug) printf("found minseg vs. save_max inconsistency\n");
if (dinit) inconsistent=1;
min_imax = c;
minseg[min_imax] = save_max;
/* not needed for analysis, but shouldn't hurt either */
if (debug) polygon_point(&save_min);
} /* !inconsistent */
/*
* Pass 5: decide on a new freq */
if (inconsistent) {
printf("# inconsistent\n");
} else {
delta_f = find_df(&both_sides_now);
if (debug) printf("find_df() = %e\n", delta_f);
delta_f += find_df_center(&save_min,&save_max, delta_f);
delta_freq = delta_f*65536+.5;
if (debug) printf("delta_f %f delta_freq %d bsn %d\n", delta_f, delta_freq, both_sides_now);
computed_freq -= delta_freq;
printf ("# box [( %.3f , %.1f ) ", save_min.slope, save_min.offset);
printf ( " ( %.3f , %.1f )] ", save_max.slope, save_max.offset);
printf (" delta_f %.3f computed_freq %d\n", delta_f, computed_freq);
if (computed_freq < -6000000) computed_freq=-6000000;
if (computed_freq > 6000000) computed_freq= 6000000;
}
}
rp = (rp+1)%RING_SIZE;
return computed_freq;
}
makefile:
# Under Solaris, you need to
# CFLAGS += -xO2 -Xc
# LDLIBS += -lnsl -lsocket
# Some versions of Linux may need
# CFLAGS += -D_GNU_SOURCE
# To cross-compile
# CC = arm-linux-gcc
CFLAGS += -Wall -O
all: ntpclient
test: ntpclient
./ntpclient -d -r .dat
ntpclient: ntpclient.o phaselock.o
clean:
rm -f ntpclient *.o