NTP时间同步

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

你可能感兴趣的:(NTP)