home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
nisttime.carsoncity.k12.mi.us
/
nisttime.carsoncity.k12.mi.us.tar
/
nisttime.carsoncity.k12.mi.us
/
pub
/
lockclock
/
getdif.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-18
|
9KB
|
283 lines
#include "sizint.h"
int cmadr;
int cmport; /*define the global comport number*/
int getdif(daym,fdaym,delta,xsigma,lsflag,sigmam)
LONG *daym; /*MJD of time comparsion*/
LONG *fdaym; /*time of comparison in seconds after midnight*/
double *delta; /*time difference, local-remote*/
double xsigma; /*tolerance for consecutive differences*/
int *lsflag; /*leap second flag set on received time */
double *sigmam; /*noise in current measurements */
{
/*
this subroutine measures the difference between ACTS and
the local clock. it is a stripped-down version of NISTIME
without most of the flexibility of that program. the
configuration file of that program is not used here --
the corresponding variables are set via include files
on the assumption that they will not change once the
program is built.
*/
#include <stdio.h>
#include "getdif.h"
#ifdef IBMPC
#include <dos.h>
#endif
char buf[280];
void wrtbuf(),inilin_l(),hangup();
void putmsg(char *);
char msgbuf[80];
int diftim();
int rdbuf();
int dial(int);
int j;
int len;
int lim;
int tmo = 0;
char ie1 = '*';
char ie2 = '#';
char ie3 = -120;
char ie3a= '>'; /* changed to allow titles to terminate with > after OTM */
LONG mjd[3]; /*MJD of time difference from diftim*/
LONG fday[3]; /*time of time difference from diftim*/
double diff[3]; /*time difference from diftim*/
int ls[3]; /*leap second flag read from transmissions*/
int kbig,kmid,ksml; /*largest, middle, smallest difference*/
int conserr; /*consecutive errors from diftim*/
int alt_num; /*force dialing of alternate number if 1 */
int dialstat; /*status returned from dial subroutine */
int difstat; /*pass dialstat back through difstat*/
int difretry; /*retry count on time-out */
/*
following constant sets timeout value for read.
this version (7 jan 92) uses a time-out value that is
specified directly in ticks and is not scaled by
the cpu speed for the PC version. the value is
therefore independent of BIOS/non-BIOS access and
machine speed.
*/
#ifdef IBMPC
int ttmo = -72; /*72 ticks is about 4 seconds */
#endif
#ifdef SUN
int ttmo = -20;
#endif
/*
initialize serial line. subroutine is variant
of inilin version used in ACTS.
*/
inilin_l();
/*
following code sets number of times first loop is done.
previous versions had a different limit for 300 bits/s, but
there is no difference in this version since the time can
now be set at either speed.
*/
lim=8;
alt_num = 0; /*start out with standard ACTS number*/
difstat = 0; /*normal return status*/
difretry = 3; /*allow 3 retries on a time-out*/
/*
now dial number -- continue if dial status shows connect.
if dial subroutine cannot connect then return dialer
status to caller. this will be a negative integer from
-1 to -5 if there is a modem error and
0 if there is no answer or the line is busy.
if the connection is lost while data are being received,
then the subroutine returns a status of -6 (if the loss
is in the first 6 lines) and -7 after that.
A status return of +1 is okay, +2 is okay but one value
does not agree with the others and +3 means that none
of the values agree with each other.
*/
redial: /*come here to redial on alternate number*/
if( (dialstat=dial(alt_num) ) < 1)
{
sprintf(msgbuf,"\n getdif-1, dialstat= %d alt_num= %d difstat=%d",
dialstat,alt_num,difstat);
putmsg(msgbuf);
hangup(); /*be sure modem has hung-up*/
if(alt_num++ == 0)
{
difstat = 10;
goto redial;
}
close(cmport);
return(dialstat);
}
/*
now start reading from line
note that 6 lines will be read followed by a time set.
time-set. note that this version does not distinguish between
300 and 1200.
*/
for(j=0; j<lim; j++)
{
len=rdbuf(buf,ie1,ie2,ie3a,ttmo);
if( (len > 0) && (buf[0] > 0) )
wrtbuf(&buf[len-1]); /* echo terminating character */
else
{
hangup();
sprintf(msgbuf,"\n getdif -2, timeout, difstat=%d retry=%d",
difstat,difretry);
putmsg(msgbuf);
if(difretry-- > 0) goto redial; /*just try again*/
if(alt_num++ == 0) /*try again on other number*/
{
difstat= 10;
difretry = 3;
goto redial; /*try again on alternate*/
}
close(cmport);
return(-6); /*time out error */
}
}
if(dialstat == 11) difstat = 10; /*alternate number*/
/*
now read next lines and then check the time for each
one
*/
j=0; /*loop counter */
conserr=3; /*consecutive error counter*/
while(j < 3)
{
len=rdbuf(buf,ie1,ie2,ie3,ttmo);
if( (len > 0) && (buf[0] > 0) )
{
wrtbuf(&buf[len-1]);
/*
if diftim returns okay status then advance counter
and go around again. otherwise do not count this
line and try again. give up if too many consecutive
errors
*/
if(diftim(buf,&mjd[j],&fday[j],&diff[j],&ls[j]) == 0) j++;
else conserr--; /*decrement consecutive errors*/
/*
return error status if terminator was not # or if there
were too many consecutive errors
*/
if( (buf[len-1] != ie2) || (conserr < 0) )
{
hangup();
close(cmport);
return(-8); /*line delay is not being measured*/
}
}
else
{
hangup();
close(cmport);
return(-7); /*connection was lost */
}
}
hangup();
close(cmport);
/*
if all leap second flags are the same then return leap
second status. if leap-second flags are not the same
on all three tries, then we have a problem. It is possible
that the day rolled over between transmissions and that
ls changed at that time. In that case, report lsflag=-1
and wait for next time. The negative signal indicates to
the caller that the current round should not be used.
*/
if( (ls[0] == ls[1]) && (ls[0] == ls[2]) ) *lsflag=ls[0];
else *lsflag= -1;
/*
sort differences into largest, smallest and
remaining one which is in between.
first find largest and smallest differences.
*/
kbig=ksml=0;
for(j=1; j<3; j++)
{
if(diff[j] > diff[kbig]) kbig=j; /*this is larger*/
if(diff[j] < diff[ksml]) ksml=j; /*this is smaller*/
}
switch(kbig+ksml)
{
case 1: /*kbig,ksml = 0,1 or 1,0*/
kmid=2;
break;
case 2: /*kbig,ksml = 0,2 or 2,0*/
kmid=1;
break;
case 3: /*kbig,ksml = 1,2 or 2,1*/
kmid=0;
break;
}
/*
if all values differ by less than tolerance,
then report average. estimate sigmam as equal to
the p-p scatter. The true RMS value would be 0.35
of this value if things are really white PM and
these values are representative (one-half of 0.7).
otherwise discard single outlier if possible
otherwise report failure due to too much noise
it is also possible that the failures are because
sigma has gotten too small. The tolerance here
is actually 3 sigma in the main program, so set
sigmam to be 0.5 of sigma, which is 1.5X
the sigma in the main program.
in all cases, report time of mid-point calibration
*/
*daym=mjd[1];
*fdaym=fday[1];
if( (diff[kbig] - diff[ksml]) < xsigma)
{
*delta=(diff[0] + diff[1] + diff[2])/3;
*sigmam= diff[kbig] - diff[ksml];
return(1+difstat); /*add 10 if from alternate number*/
}
/*
we have some kind of trouble -- the values differ
by more than expected value.
test to see if diff[ksml] is the outlier
*/
if( ( (diff[kbig] - diff[kmid]) < xsigma) &&
( (diff[kmid] - diff[ksml]) >= xsigma) )
{
*delta=(diff[kbig] + diff[kmid])/2;
*sigmam=0.5*xsigma;
/*
show one point dropped
*/
return(2+difstat);
}
/*
test to see if diff[kbig] is the outlier
*/
if( ( (diff[kbig] - diff[kmid]) >= xsigma) &&
( (diff[kmid] - diff[ksml]) < xsigma) )
{
*delta=(diff[kmid] + diff[ksml])/2;
*sigmam=0.5*xsigma;
return(2+difstat);
}
/*
if we get here then there are two remaining possibilities:
either both differences are <~ sigma so that
diff[kbig]-diff[ksml] is of order 2 sigma but neither
kbig nor ksml is an outlier because both differences
are about the same or
all of them differ from each other by more sigma
report average but show noisy status. a return
value of 4 means that either this cycle is unusually
noise or sigma is a bit too small. a return value
of 3 probably means that something is wrong.
*/
*delta=(diff[0] + diff[1] + diff[2])/3;
*sigmam=0.5*xsigma;
if( (diff[kbig] - diff[ksml]) <= 2*xsigma) return(4+difstat);
else return(3+difstat);
}