#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS)
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
#include "ntp_calendar.h"
#include <ctype.h>
#if defined(HAVE_BSD_TTYS)
#include <sgtty.h>
#endif
#if defined(HAVE_SYSV_TTYS)
#include <termio.h>
#endif
#if defined(HAVE_TERMIOS)
#include <termios.h>
#endif
#if defined(STREAM)
#include <stropts.h>
#endif
#ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
#endif
#ifdef HAVE_SYS_PPSCLOCK_H
# include <sys/ppsclock.h>
#endif
#include "ntp_stdlib.h"
int dbg = 0;
#ifndef MAXUNITS
#define MAXUNITS 4
#endif
#ifndef EES232
#define EES232 "/dev/ees%d"
#endif
#ifndef EESPRECISION
#define EESPRECISION (-10)
#endif
#ifndef EESREFID
#define EESREFID "MSF\0"
#endif
#ifndef EESHSREFID
#define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8))
#endif
#define EESDESCRIPTION "EES M201 MSF Receiver"
#ifndef SPEED232
#define SPEED232 B9600
#endif
#define SAFETY_SHIFT 10
#define BITS_TO_L_FP(bits, baud) \
(((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
#define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600)
#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
#ifndef STREAM_PP1
#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
#endif
#ifndef STREAM_PP2
#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
#endif
#define EESM_CSEC 0
#define EESM_SEC 1
#define EESM_MIN 2
#define EESM_HOUR 3
#define EESM_DAYWK 4
#define EESM_DAY 5
#define EESM_MON 6
#define EESM_YEAR 7
#define EESM_LEAP 8
#define EESM_BST 9
#define EESM_MSFOK 10
#define LENEESPRT (EESM_MSFOK+1)
#define LENEESCODE (LENEESPRT+1)
#define EESCS_WAIT 0
#define EESCS_GOTSOME 1
#define DEFFUDGETIME 0
#ifndef DEFOSTIME
#define DEFOSTIME 0
#endif
#define DEFINHTIME INH_DELAY_PPS
#define FULLSHIFT 6
#define NCODES (1<< FULLSHIFT)
#define REDUCESHIFT (FULLSHIFT -1)
#define BESTSAMPLE ((samplereduce * 3) /4)
#define EESLEAPHOLD (40 * 60)
#define EES_STEP_F (1 << 24)
#define EES_STEP_F_GRACE (EES_STEP_F/8)
#define EES_STEP_NOTE (1 << 21)
#define EES_STEP_NOTES 50
#define MAX_STEP 16
#define DB_SYSLOG_SMPLI 0x0001
#define DB_SYSLOG_SMPLE 0x0002
#define DB_SYSLOG_SMTHI 0x0004
#define DB_SYSLOG_NSMTHE 0x0008
#define DB_SYSLOG_NSMTHI 0x0010
#define DB_SYSLOG_SMTHE 0x0020
#define DB_PRINT_EV 0x0040
#define DB_PRINT_CDT 0x0080
#define DB_PRINT_CDTC 0x0100
#define DB_SYSLOG_KEEPD 0x0800
#define DB_SYSLOG_KEEPE 0x1000
#define DB_LOG_DELTAS 0x2000
#define DB_PRINT_DELTAS 0x4000
#define DB_LOG_AWAITMORE 0x8000
#define DB_LOG_SAMPLES 0x10000
#define DB_NO_PPS 0x20000
#define DB_INC_PPS 0x40000
#define DB_DUMP_DELTAS 0x80000
struct eesunit {
struct peer *peer;
struct refclockio io;
l_fp reftime;
l_fp lastsampletime;
l_fp arrvtime;
l_fp codeoffsets[NCODES];
l_fp offset;
l_fp lowoffset;
l_fp highoffset;
char lastcode[LENEESCODE+6];
u_long lasttime;
u_long clocklastgood;
u_char lencode;
u_char nsamples;
u_char codestate;
u_char unit;
u_char status;
u_char lastevent;
u_char reason;
u_char hour;
u_char minute;
u_char second;
char tz;
u_char ttytype;
u_char dump_vals;
u_char usealldata;
u_short day;
u_long yearstart;
u_long leaphold;
u_long badformat;
u_long baddata;
u_long timestarted;
long last_pps_no;
char fix_pending;
l_fp last_l;
u_char last_steps[MAX_STEP];
int best_av_step;
char best_av_step_count;
char this_step;
int last_step_late;
long jump_fsecs;
u_long last_step;
int last_step_secs;
int using_ramp;
};
#define last_sec last_l.l_ui
#define last_sfsec last_l.l_f
#define this_uisec ((ees->arrvtime).l_ui)
#define this_sfsec ((ees->arrvtime).l_f)
#define msec(x) ((x) / (1<<22))
#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0])
#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
#define T_CBREAK 1
#define T_PPS 8
#define is_cbreak(x) ((x)->ttytype & T_CBREAK)
#define is_pps(x) ((x)->ttytype & T_PPS)
#define is_any(x) ((x)->ttytype)
#define CODEREASON 20
static struct eesunit *eesunits[MAXUNITS];
static u_char unitinuse[MAXUNITS];
static l_fp inherent_delay[MAXUNITS];
static l_fp fudgefactor[MAXUNITS];
static l_fp os_delay[MAXUNITS];
static l_fp offset_fudge[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char sloppyclockflag[MAXUNITS];
static int deltas[60];
static l_fp acceptable_slop;
static l_fp onesec;
#ifndef DUMP_BUF_SIZE
#define DUMP_BUF_SIZE 10112
#endif
#define ees_reset(ees) (ees)->nsamples = 0; \
(ees)->codestate = EESCS_WAIT
#define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
ees_report_event((ees), (evcode))
#define USECS 1000000
#define MINSTEP 5
#define MAXLOOPS (USECS/9)
static int msfees_start P((int unit, struct peer *peer));
static void msfees_shutdown P((int unit, struct peer *peer));
static void msfees_poll P((int unit, struct peer *peer));
static void msfees_init P((void));
static void dump_buf P((l_fp *coffs, int from, int to, char *text));
static void ees_report_event P((struct eesunit *ees, int code));
static void ees_receive P((struct recvbuf *rbufp));
static void ees_process P((struct eesunit *ees));
#ifdef QSORT_USES_VOID_P
static int offcompare P((const void *va, const void *vb));
#else
static int offcompare P((const l_fp *a, const l_fp *b));
#endif
struct refclock refclock_msfees = {
msfees_start,
msfees_shutdown,
msfees_poll,
noentry,
msfees_init,
noentry,
NOFLAGS
};
static void
dump_buf(
l_fp *coffs,
int from,
int to,
char *text
)
{
char buff[DUMP_BUF_SIZE + 80];
int i;
register char *ptr = buff;
sprintf(ptr, text);
for (i=from; i<to; i++)
{ while (*ptr) ptr++;
if ((ptr-buff) > DUMP_BUF_SIZE) msyslog(LOG_DEBUG, "D: %s", ptr=buff);
sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
}
msyslog(LOG_DEBUG, "D: %s", buff);
}
static void
msfees_init(void)
{
register int i;
memset((char *)eesunits, 0, sizeof eesunits);
memset((char *)unitinuse, 0, sizeof unitinuse);
acceptable_slop.l_ui = 0;
acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
onesec.l_ui = 1;
onesec.l_uf = 0;
for (i = 0; i < MAXUNITS; i++) {
fudgefactor[i].l_ui = 0;
fudgefactor[i].l_uf = DEFFUDGETIME;
os_delay[i].l_ui = 0;
os_delay[i].l_uf = DEFOSTIME;
inherent_delay[i].l_ui = 0;
inherent_delay[i].l_uf = DEFINHTIME;
offset_fudge[i] = os_delay[i];
L_ADD(&offset_fudge[i], &fudgefactor[i]);
L_ADD(&offset_fudge[i], &inherent_delay[i]);
stratumtouse[i] = 0;
sloppyclockflag[i] = 0;
}
}
static int
msfees_start(
int unit,
struct peer *peer
)
{
register struct eesunit *ees;
register int i;
int fd232 = -1;
char eesdev[20];
struct termios ttyb, *ttyp;
struct refclockproc *pp;
pp = peer->procptr;
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
unit, MAXUNITS-1);
return 0;
}
if (unitinuse[unit]) {
msyslog(LOG_ERR, "ees clock: unit number %d in use", unit);
return 0;
}
(void) sprintf(eesdev, EES232, unit);
fd232 = open(eesdev, O_RDWR, 0777);
if (fd232 == -1) {
msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
return 0;
}
#ifdef TIOCEXCL
if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
goto screwed;
}
#endif
ttyp = &ttyb;
if (tcgetattr(fd232, ttyp) < 0) {
msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
goto screwed;
}
ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
ttyp->c_oflag = 0;
ttyp->c_lflag = ICANON;
ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
goto screwed;
}
if (tcflush(fd232, TCIOFLUSH) < 0) {
msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
goto screwed;
}
inherent_delay[unit].l_uf = INH_DELAY_PPS;
offset_fudge[unit] = os_delay[unit];
L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
if (eesunits[unit] != 0)
ees = eesunits[unit];
else {
for (i = 0; i < MAXUNITS; i++) {
if (!unitinuse[i] && eesunits[i] != 0)
break;
}
if (i < MAXUNITS) {
ees = eesunits[i];
eesunits[i] = 0;
}
else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
}
memset((char *)ees, 0, sizeof(struct eesunit));
eesunits[unit] = ees;
ees->peer = peer;
ees->unit = (u_char)unit;
ees->timestarted= current_time;
ees->ttytype = 0;
ees->io.clock_recv= ees_receive;
ees->io.srcclock= (caddr_t)ees;
ees->io.datalen = 0;
ees->io.fd = fd232;
#ifdef STREAM
{
int rc1;
while (ioctl(fd232, I_POP, 0 ) >= 0) ;
if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
msyslog(LOG_ERR,
"ees clock: Push of `%s' and `%s' to %s failed %m",
STREAM_PP1, STREAM_PP2, eesdev);
goto screwed;
}
else {
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
(rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
ees->ttytype |= T_PPS;
}
}
#endif
if (!io_addclock(&ees->io)) {
msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
goto screwed;
}
peer->precision = sys_precision;
peer->stratum = stratumtouse[unit];
if (stratumtouse[unit] <= 1) {
memcpy((char *)&pp->refid, EESREFID, 4);
if (unit > 0 && unit < 10)
((char *)&pp->refid)[3] = '0' + unit;
} else {
peer->refid = htonl(EESHSREFID);
}
unitinuse[unit] = 1;
pp->unitptr = (caddr_t) &eesunits[unit];
pp->clockdesc = EESDESCRIPTION;
msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
return (1);
screwed:
if (fd232 != -1)
(void) close(fd232);
return (0);
}
static void
msfees_shutdown(
int unit,
struct peer *peer
)
{
register struct eesunit *ees;
if (unit >= MAXUNITS) {
msyslog(LOG_ERR,
"ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
unit, MAXUNITS);
return;
}
if (!unitinuse[unit]) {
msyslog(LOG_ERR,
"ees clock: INTERNAL ERROR, unit number %d not in use", unit);
return;
}
ees = eesunits[unit];
io_closeclock(&ees->io);
unitinuse[unit] = 0;
}
static void
ees_report_event(
struct eesunit *ees,
int code
)
{
if (ees->status != (u_char)code) {
ees->status = (u_char)code;
if (code != CEVNT_NOMINAL)
ees->lastevent = (u_char)code;
}
}
static void
ees_receive(
struct recvbuf *rbufp
)
{
register int n_sample;
register int day;
register struct eesunit *ees;
register u_char *dpt;
register u_char *dpend;
register char *cp;
l_fp tmp;
int call_pps_sample = 0;
l_fp pps_arrvstamp;
int sincelast;
int pps_step = 0;
int suspect_4ms_step = 0;
struct ppsclockev ppsclockev;
long *ptr = (long *) &ppsclockev;
int rc;
int request;
#ifdef HAVE_CIOGETEV
request = CIOGETEV;
#endif
#ifdef HAVE_TIOCGPPSEV
request = TIOCGPPSEV;
#endif
ees = (struct eesunit *)rbufp->recv_srcclock;
dpt = (u_char *)&rbufp->recv_space;
dpend = dpt + rbufp->recv_length;
if ((dbg & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
printf("[%d] ", rbufp->recv_length);
switch (ees->codestate) {
case EESCS_WAIT:
ees->arrvtime = rbufp->recv_time;
ees->codestate = EESCS_GOTSOME;
ees->lencode = 0;
case EESCS_GOTSOME:
cp = &(ees->lastcode[ees->lencode]);
while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
*cp++ = (char)*dpt++;
ees->lencode++;
if (ees->lencode > LENEESPRT) {
NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO,
"I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
ees->lencode, dpend - dpt, LENEESPRT,
#define D(x) (ees->lastcode[x])
D(0), D(1), D(2), D(3), D(4), D(5), D(6),
D(7), D(8), D(9), D(10), D(11), D(12));
#undef D
ees->badformat++;
ees->reason = CODEREASON + 1;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
}
if (dpt == dpend) {
if (dbg & DB_LOG_AWAITMORE)
msyslog(LOG_INFO,
"I: ees clock %d: %p == %p: await more",
ees->unit, dpt, dpend);
return;
}
if ((*dpt & 0x7f) != 0x7f) {
msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
ees->badformat++;
ees->reason = CODEREASON + 2;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
dpt++;
cp = ees->lastcode;
break;
default:
msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
ees->unit, ees->codestate);
ees->reason = CODEREASON + 5;
ees_event(ees, CEVNT_FAULT);
ees_reset(ees);
return;
}
ees->codestate = EESCS_WAIT;
ees->lasttime = current_time;
if (ees->lencode != LENEESPRT) {
ees->badformat++;
ees->reason = CODEREASON + 6;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
cp = ees->lastcode;
if (cp[EESM_CSEC] != 0) {
ees->baddata++;
ees->reason = CODEREASON + 7;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
ees->badformat++;
ees->reason = CODEREASON + 8;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
ees->badformat++;
ees->reason = CODEREASON + 9;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
ees->badformat++;
ees->reason = CODEREASON + 10;
ees_event(ees, CEVNT_BADREPLY);
ees_reset(ees);
return;
}
#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
#define istrue(x) ((x)?1:0)
ees->second = bcdunpack(cp[EESM_SEC]);
ees->minute = bcdunpack(cp[EESM_MIN]);
ees->hour = bcdunpack(cp[EESM_HOUR]);
day = bcdunpack(cp[EESM_DAY]);
switch (bcdunpack(cp[EESM_MON])) {
case 12: day += NOV;
case 11: day += OCT;
case 10: day += SEP;
case 9: day += AUG;
case 8: day += JUL;
case 7: day += JUN;
case 6: day += MAY;
case 5: day += APR;
case 4: day += MAR;
case 3: day += FEB;
if (istrue(cp[EESM_LEAP])) day++;
case 2: day += JAN;
case 1: break;
default: ees->baddata++;
ees->reason = CODEREASON + 11;
ees_event(ees, CEVNT_BADDATE);
ees_reset(ees);
return;
}
ees->day = day;
ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
if (ees->day > 366 || ees->day < 1 ||
ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
ees->baddata++;
ees->reason = CODEREASON + 12;
ees_event(ees, CEVNT_BADDATE);
ees_reset(ees);
return;
}
n_sample = ees->nsamples;
if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
&tmp.l_ui)) {
ees->baddata++;
ees->reason = CODEREASON + 13;
ees_event(ees, CEVNT_BADDATE);
ees_reset(ees);
return;
}
tmp.l_uf = 0;
ees->lastsampletime = tmp;
if (istrue(cp[EESM_MSFOK])) {
ees->reftime = tmp;
ees->clocklastgood = current_time;
}
ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
ees->codeoffsets[n_sample].l_uf = 0;
sincelast = this_uisec - ees->last_step;
memset((char *) &ppsclockev, 0, sizeof ppsclockev);
rc = ioctl(ees->io.fd, request, (char *) &ppsclockev);
if (dbg & DB_PRINT_EV) fprintf(stderr,
"[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n",
DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees),
rc, errno, ptr[0], ptr[1], ptr[2]);
if (rc >= 0) {
int conv = -1;
pps_step = ppsclockev.serial - ees->last_pps_no;
if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
if (pps_step != 1 && pps_step != 2)
fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
ppsclockev.serial, ees->last_pps_no, pps_step);
else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
fprintf(stderr, "buftvtots failed\n");
else {
l_fp diff;
diff = pps_arrvstamp;
conv = 0;
L_SUB(&diff, &ees->arrvtime);
if (dbg & DB_PRINT_CDT)
printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s",
DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf,
(long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf,
(long)diff.l_ui, (long)diff.l_uf,
ctime(&(ppsclockev.tv.tv_sec)));
if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
L_SUB(&diff, &acceptable_slop);
if (L_ISNEG(&diff)) {
ees->arrvtime = pps_arrvstamp;
conv++;
call_pps_sample++;
}
else if (ees->second == 1) {
diff = pps_arrvstamp;
L_ADD(&diff, &onesec);
L_SUB(&diff, &ees->arrvtime);
if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
L_SUB(&diff, &acceptable_slop);
msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
pps_arrvstamp.l_uf,
ees->arrvtime.l_uf,
diff.l_ui, diff.l_uf,
(int)ppsclockev.tv.tv_usec,
ctime(&(ppsclockev.tv.tv_sec)));
if (L_ISNEG(&diff)) {
suspect_4ms_step |= 2;
ees->arrvtime = pps_arrvstamp;
L_ADD(&ees->arrvtime, &onesec);
conv++;
call_pps_sample++;
}
}
}
ees->last_pps_no = ppsclockev.serial;
if (dbg & DB_PRINT_CDTC)
printf(
"[%x] %08lx %08lx %d u%d (%d %d)\n",
DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui,
(long)pps_arrvstamp.l_uf, conv, ees->unit,
call_pps_sample, pps_step);
}
{ l_fp delta;
#define delta_isec delta.l_ui
#define delta_ssec delta.l_i
#define delta_sfsec delta.l_f
long delta_f_abs;
delta.l_i = ees->arrvtime.l_i;
delta.l_f = ees->arrvtime.l_f;
L_SUB(&delta, &ees->last_l);
delta_f_abs = delta_sfsec;
if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
if (dbg & DB_DUMP_DELTAS)
{ if (
ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
if (ees->second == 1) {
char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
char *cptr=text;
int i;
for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
sprintf(cptr, " %d.%04d",
msec(deltas[i]), subms(deltas[i]));
while (*cptr) cptr++;
}
msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
text+1);
for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
}
}
if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
(delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
(ees->second == 0 || ees->second == 1 || ees->second == 2) &&
(sincelast < 0 || sincelast > 122)
) {
int old_sincelast;
int count=0;
int sum = 0;
if (ees->last_step == 0) sincelast = 0;
old_sincelast = sincelast;
if(ees->last_step) {
int other_step = 0;
int third_step = 0;
int this_step = (sincelast + (60 /2)) / 60;
int p_step = ees->this_step;
int p;
ees->last_steps[p_step] = this_step;
p= p_step;
p_step++;
if (p_step >= LAST_STEPS) p_step = 0;
ees->this_step = p_step;
while (p != p_step) {
int this = ees->last_steps[p];
if (this == 0) break;
if (this != this_step) {
if (other_step == 0 && (
this== (this_step +2) ||
this== (this_step -2) ||
this== (this_step +1) ||
this== (this_step -1)))
other_step = this;
if (other_step != this) {
int idelta = (this_step - other_step);
if (idelta < 0) idelta = - idelta;
if (third_step == 0 && (
(idelta == 1) ? (
this == (other_step +1) ||
this == (other_step -1) ||
this == (this_step +1) ||
this == (this_step -1))
:
(
this == (this_step + other_step)/2
)
)) third_step = this;
if (third_step != this) break;
}
}
sum += this;
p--;
if (p < 0) p += LAST_STEPS;
count++;
}
msyslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step);
if (count != 0) sum = ((sum * 60) + (count /2)) / count;
#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
#undef SV
ees->jump_fsecs = delta_sfsec;
ees->using_ramp = 1;
if (sincelast > 170)
ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
else ees->last_step_late = 30;
if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
if (ees->last_step_late < 0) ees->last_step_late = 0;
if (ees->last_step_late >= 60) ees->last_step_late = 59;
sincelast = 0;
}
else {
ees->last_step_late = 30;
ees->jump_fsecs = delta_sfsec;
ees->using_ramp = 1;
sum = 4 * 60;
}
ees->last_step = this_uisec;
printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n",
ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
ees->second, old_sincelast, ees->last_step_late, count, sum,
ees->last_step_secs);
msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second,
old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
if (sum) ees->last_step_secs = sum;
}
else {
if (suspect_4ms_step) msyslog(LOG_ERR,
"MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
msec(EES_STEP_F - EES_STEP_F_GRACE),
subms(EES_STEP_F - EES_STEP_F_GRACE),
(int)msec(delta_f_abs),
(int)subms(delta_f_abs),
msec(EES_STEP_F + EES_STEP_F_GRACE),
subms(EES_STEP_F + EES_STEP_F_GRACE),
ees->second,
sincelast);
if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
static int ees_step_notes = EES_STEP_NOTES;
if (ees_step_notes > 0) {
ees_step_notes--;
printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n",
ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
}
}
}
}
ees->last_l = ees->arrvtime;
if (ees->using_ramp &&
sincelast < (ees->last_step_secs)*2 &&
ees->last_step_secs)
{ long sec_of_ramp = sincelast + ees->last_step_late;
long fsecs;
l_fp inc;
if (sec_of_ramp > (ees->last_step_secs + 120))
sec_of_ramp = ees->last_step_secs;
fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs);
if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
"[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)",
DB_LOG_DELTAS,
ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
if (dbg & DB_PRINT_DELTAS) printf(
"MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n",
ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
(long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
inc.l_i = (fsecs < 0) ? -1 : 0;
inc.l_f = fsecs;
if (dbg & DB_INC_PPS)
{ L_SUB(&pps_arrvstamp, &inc);
L_SUB(&ees->arrvtime, &inc);
}
else
{ L_ADD(&pps_arrvstamp, &inc);
L_ADD(&ees->arrvtime, &inc);
}
}
else {
if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
"[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
DB_LOG_DELTAS,
ees->unit, ees->using_ramp,
sincelast,
(ees->last_step_secs)*2,
ees->last_step_secs);
if (dbg & DB_PRINT_DELTAS) printf(
"[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
DB_LOG_DELTAS,
ees->unit, ees->using_ramp,
sincelast,
(ees->last_step_secs)*2,
ees->last_step_secs);
}
L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
if (call_pps_sample && !(dbg & DB_NO_PPS)) {
L_NEG(&pps_arrvstamp);
}
L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
if (dbg & DB_LOG_SAMPLES) msyslog(LOG_ERR,
"MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
ees->unit, DB_LOG_DELTAS, n_sample,
ees->codeoffsets[n_sample].l_f,
ees->codeoffsets[n_sample].l_f / 4295,
pps_arrvstamp.l_f,
pps_arrvstamp.l_f /4295,
(dbg & DB_NO_PPS) ? " [no PPS]" : "");
if (ees->nsamples++ == NCODES-1) ees_process(ees);
}
#ifdef QSORT_USES_VOID_P
static int
offcompare(
const void *va,
const void *vb
)
{
const l_fp *a = (const l_fp *)va;
const l_fp *b = (const l_fp *)vb;
return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
}
#else
static int
offcompare(
const l_fp *a,
const l_fp *b
)
{
return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
}
#endif
static void
ees_process(
struct eesunit *ees
)
{
static int last_samples = -1;
register int i, j;
register int noff;
register l_fp *coffs = ees->codeoffsets;
l_fp offset, tmp;
double dispersion;
int lostsync, isinsync;
int samples = ees->nsamples;
int samplelog = 0;
int samplereduce = (samples + 1) / 2;
double doffset;
ees_reset(ees);
if (sloppyclockflag[ees->unit]) {
samplelog = (samples < 2) ? 0 :
(samples < 5) ? 1 :
(samples < 9) ? 2 :
(samples < 17) ? 3 :
(samples < 33) ? 4 : 5;
samplereduce = (1 << samplelog);
}
if (samples != last_samples &&
((samples != (last_samples-1)) || samples < 3)) {
msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
samples, last_samples, samplereduce);
last_samples = samples;
}
if (samples < 1) return;
if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
qsort(
#ifdef QSORT_USES_VOID_P
(void *)
#else
(char *)
#endif
coffs, (size_t)samples, sizeof(l_fp), offcompare);
noff = samples;
i = 0;
while ((noff - i) > samplereduce) {
tmp = coffs[(noff + i)/2];
L_ADD(&tmp, &tmp);
L_SUB(&tmp, &coffs[i]);
L_SUB(&tmp, &coffs[noff-1]);
if (L_ISNEG(&tmp)) noff--; else i++;
}
if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:");
if (sloppyclockflag[ees->unit]) {
offset.l_ui = offset.l_uf = 0;
for (j = i; j < noff; j++)
L_ADD(&offset, &coffs[j]);
for (j = samplelog; j > 0; j--)
L_RSHIFTU(&offset);
}
else offset = coffs[i+BESTSAMPLE];
tmp = coffs[noff-1];
L_SUB(&tmp, &coffs[i]);
#define FRACT_SEC(n) ((1 << 30) / (n/2))
dispersion = LFPTOFP(&tmp) / 2;
if (dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog(
(dbg & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
"I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d",
dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
offset.l_f / 4295, offset.l_f,
(dispersion * 1526) / 100,
(sloppyclockflag[ees->unit]) ? " by averaging" : "",
FRACT_SEC(10) / 4295,
(coffs[0].l_f) / 4295,
i,
(coffs[i].l_f) / 4295,
(coffs[samples/2].l_f) / 4295,
(coffs[i+BESTSAMPLE].l_f) / 4295,
noff-1,
(coffs[noff-1].l_f) / 4295,
(coffs[samples-1].l_f) / 4295);
if (ees->usealldata && ees->offset.l_uf) {
long diff = (long) (ees->offset.l_uf - offset.l_uf);
if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
int samd = (64 * 4) / samples;
long new;
if (samd < 2) samd = 2;
new = offset.l_uf + ((diff * (samd -1)) / samd);
if ((new & 0x80000000) !=
(((long) offset.l_uf) & 0x80000000))
{ NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), so add %d",
new & 0x80000000,
((long) offset.l_uf) & 0x80000000,
new, (long) offset.l_uf,
(new < 0) ? -1 : 1);
offset.l_ui += (new < 0) ? -1 : 1;
}
dispersion /= 4;
if (dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) msyslog(
(dbg & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
"I: [%x] Smooth data: %ld -> %ld, dispersion now %f",
dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
((long) offset.l_uf) / 4295, new / 4295,
(dispersion * 1526) / 100);
offset.l_uf = (unsigned long) new;
}
else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
(dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
"[%x] No smooth as delta not %d < %ld < %d",
dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
- FRACT_SEC(100), diff, FRACT_SEC(100));
}
else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
(dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
"I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
offset.l_f, ees->offset.l_f - offset.l_f);
ees->offset = offset;
ees->lowoffset = coffs[i];
ees->highoffset = coffs[noff-1];
lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
if (ees->fix_pending) {
msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
ees->fix_pending = 0;
}
LFPTOD(&offset, doffset);
refclock_receive(ees->peer);
ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
}
static void
msfees_poll(
int unit,
struct peer *peer
)
{
if (unit >= MAXUNITS) {
msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
unit);
return;
}
if (!unitinuse[unit]) {
msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
unit);
return;
}
ees_process(eesunits[unit]);
if ((current_time - eesunits[unit]->lasttime) > 150)
ees_event(eesunits[unit], CEVNT_FAULT);
}
#else
int refclock_msfees_bs;
#endif