Annotation of embedaddon/ntp/ntpd/refclock_msfees.c, revision 1.1.1.1

1.1       misho       1: /* refclock_ees - clock driver for the EES M201 receiver */
                      2: 
                      3: #ifdef HAVE_CONFIG_H
                      4: #include <config.h>
                      5: #endif
                      6: 
                      7: #if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS)
                      8: 
                      9: /* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
                     10:  * were removed as the code was overly hairy, they weren't in use
                     11:  * (hence probably didn't work).  Still in RCS file at cl.cam.ac.uk
                     12:  */
                     13: 
                     14: #include "ntpd.h"
                     15: #include "ntp_io.h"
                     16: #include "ntp_refclock.h"
                     17: #include "ntp_unixtime.h"
                     18: #include "ntp_calendar.h"
                     19: 
                     20: #include <ctype.h>
                     21: #if defined(HAVE_BSD_TTYS)
                     22: #include <sgtty.h>
                     23: #endif /* HAVE_BSD_TTYS */
                     24: #if defined(HAVE_SYSV_TTYS)
                     25: #include <termio.h>
                     26: #endif /* HAVE_SYSV_TTYS */
                     27: #if defined(HAVE_TERMIOS)
                     28: #include <termios.h>
                     29: #endif
                     30: #if defined(STREAM)
                     31: #include <stropts.h>
                     32: #endif
                     33: 
                     34: #ifdef HAVE_SYS_TERMIOS_H
                     35: # include <sys/termios.h>
                     36: #endif
                     37: #ifdef HAVE_SYS_PPSCLOCK_H
                     38: # include <sys/ppsclock.h>
                     39: #endif
                     40: 
                     41: #include "ntp_stdlib.h"
                     42: 
                     43: int dbg = 0;
                     44: /*
                     45:        fudgefactor     = fudgetime1;
                     46:        os_delay        = fudgetime2;
                     47:           offset_fudge = os_delay + fudgefactor + inherent_delay;
                     48:        stratumtouse    = fudgeval1 & 0xf
                     49:        dbg             = fudgeval2;
                     50:        sloppyclockflag = flags & CLK_FLAG1;
                     51:                1         log smoothing summary when processing sample
                     52:                4         dump the buffer from the clock
                     53:                8         EIOGETKD the last n uS time stamps
                     54:        if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
                     55:        ees->dump_vals  = flags & CLK_FLAG3;
                     56:        ees->usealldata = flags & CLK_FLAG4;
                     57: 
                     58: 
                     59:        bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
                     60:        bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
                     61:        bug->values[2] = (u_long)ees->status;
                     62:        bug->values[3] = (u_long)ees->lastevent;
                     63:        bug->values[4] = (u_long)ees->reason;
                     64:        bug->values[5] = (u_long)ees->nsamples;
                     65:        bug->values[6] = (u_long)ees->codestate;
                     66:        bug->values[7] = (u_long)ees->day;
                     67:        bug->values[8] = (u_long)ees->hour;
                     68:        bug->values[9] = (u_long)ees->minute;
                     69:        bug->values[10] = (u_long)ees->second;
                     70:        bug->values[11] = (u_long)ees->tz;
                     71:        bug->values[12] = ees->yearstart;
                     72:        bug->values[13] = (ees->leaphold > current_time) ?
                     73:                                ees->leaphold - current_time : 0;
                     74:        bug->values[14] = inherent_delay[unit].l_uf;
                     75:        bug->values[15] = offset_fudge[unit].l_uf;
                     76: 
                     77:        bug->times[0] = ees->reftime;
                     78:        bug->times[1] = ees->arrvtime;
                     79:        bug->times[2] = ees->lastsampletime;
                     80:        bug->times[3] = ees->offset;
                     81:        bug->times[4] = ees->lowoffset;
                     82:        bug->times[5] = ees->highoffset;
                     83:        bug->times[6] = inherent_delay[unit];
                     84:        bug->times[8] = os_delay[unit];
                     85:        bug->times[7] = fudgefactor[unit];
                     86:        bug->times[9] = offset_fudge[unit];
                     87:        bug->times[10]= ees->yearstart, 0;
                     88:        */
                     89: 
                     90: /* This should support the use of an EES M201 receiver with RS232
                     91:  * output (modified to transmit time once per second).
                     92:  *
                     93:  * For the format of the message sent by the clock, see the EESM_
                     94:  * definitions below.
                     95:  *
                     96:  * It appears to run free for an integral number of minutes, until the error
                     97:  * reaches 4mS, at which point it steps at second = 01.
                     98:  * It appears that sometimes it steps 4mS (say at 7 min interval),
                     99:  * then the next minute it decides that it was an error, so steps back.
                    100:  * On the next minute it steps forward again :-(
                    101:  * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
                    102:  * or 9.5uS/S then 3990.5uS at a 7min re-sync,
                    103:  * at which point it may lose the "00" second time stamp.
                    104:  * I assume that the most accurate time is just AFTER the re-sync.
                    105:  * Hence remember the last cycle interval,
                    106:  *
                    107:  * Can run in any one of:
                    108:  *
                    109:  *     PPSCD   PPS signal sets CD which interupts, and grabs the current TOD
                    110:  *     (sun)           *in the interupt code*, so as to avoid problems with
                    111:  *                     the STREAMS scheduling.
                    112:  *
                    113:  * It appears that it goes 16.5 uS slow each second, then every 4 mins it
                    114:  * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
                    115:  */
                    116: 
                    117: /* Definitions */
                    118: #ifndef        MAXUNITS
                    119: #define        MAXUNITS        4       /* maximum number of EES units permitted */
                    120: #endif
                    121: 
                    122: #ifndef        EES232
                    123: #define        EES232  "/dev/ees%d"    /* Device to open to read the data */
                    124: #endif
                    125: 
                    126: /* Other constant stuff */
                    127: #ifndef        EESPRECISION
                    128: #define        EESPRECISION    (-10)           /* what the heck - 2**-10 = 1ms */
                    129: #endif
                    130: #ifndef        EESREFID
                    131: #define        EESREFID        "MSF\0"         /* String to identify the clock */
                    132: #endif
                    133: #ifndef        EESHSREFID
                    134: #define        EESHSREFID      (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
                    135: #endif
                    136: 
                    137: /* Description of clock */
                    138: #define        EESDESCRIPTION          "EES M201 MSF Receiver"
                    139: 
                    140: /* Speed we run the clock port at. If this is changed the UARTDELAY
                    141:  * value should be recomputed to suit.
                    142:  */
                    143: #ifndef        SPEED232
                    144: #define        SPEED232        B9600   /* 9600 baud */
                    145: #endif
                    146: 
                    147: /* What is the inherent delay for this mode of working, i.e. when is the
                    148:  * data time stamped.
                    149:  */
                    150: #define        SAFETY_SHIFT    10      /* Split the shift to avoid overflow */
                    151: #define        BITS_TO_L_FP(bits, baud) \
                    152: (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
                    153: #define        INH_DELAY_CBREAK        BITS_TO_L_FP(119, 9600)
                    154: #define        INH_DELAY_PPS           BITS_TO_L_FP(  0, 9600)
                    155: 
                    156: #ifndef        STREAM_PP1
                    157: #define        STREAM_PP1      "ppsclocd\0<-- patch space for module name1 -->"
                    158: #endif
                    159: #ifndef        STREAM_PP2
                    160: #define        STREAM_PP2      "ppsclock\0<-- patch space for module name2 -->"
                    161: #endif
                    162: 
                    163:      /* Offsets of the bytes of the serial line code.  The clock gives
                    164:  * local time with a GMT/BST indication. The EESM_ definitions
                    165:  * give offsets into ees->lastcode.
                    166:  */
                    167: #define EESM_CSEC       0      /* centiseconds - always zero in our clock  */
                    168: #define EESM_SEC        1      /* seconds in BCD                           */
                    169: #define EESM_MIN        2      /* minutes in BCD                           */
                    170: #define EESM_HOUR       3      /* hours in BCD                             */
                    171: #define EESM_DAYWK      4      /* day of week (Sun = 0 etc)                */
                    172: #define EESM_DAY        5      /* day of month in BCD                      */
                    173: #define EESM_MON        6      /* month in BCD                             */
                    174: #define EESM_YEAR       7      /* year MOD 100 in BCD                      */
                    175: #define EESM_LEAP       8      /* 0x0f if leap year, otherwise zero        */
                    176: #define EESM_BST        9      /* 0x03 if BST, 0x00 if GMT                 */
                    177: #define EESM_MSFOK     10      /* 0x3f if radio good, otherwise zero       */
                    178:                                /* followed by a frame alignment byte (0xff) /
                    179:                                /  which is not put into the lastcode buffer*/
                    180: 
                    181: /* Length of the serial time code, in characters.  The first length
                    182:  * is less the frame alignment byte.
                    183:  */
                    184: #define        LENEESPRT       (EESM_MSFOK+1)
                    185: #define        LENEESCODE      (LENEESPRT+1)
                    186: 
                    187:      /* Code state. */
                    188: #define        EESCS_WAIT      0       /* waiting for start of timecode */
                    189: #define        EESCS_GOTSOME   1       /* have an incomplete time code buffered */
                    190: 
                    191:      /* Default fudge factor and character to receive */
                    192: #define        DEFFUDGETIME    0       /* Default user supplied fudge factor */
                    193: #ifndef        DEFOSTIME
                    194: #define        DEFOSTIME       0       /* Default OS delay -- passed by Make ? */
                    195: #endif
                    196: #define        DEFINHTIME      INH_DELAY_PPS /* inherent delay due to sample point*/
                    197: 
                    198:      /* Limits on things.  Reduce the number of samples to SAMPLEREDUCE by median
                    199:  * elimination.  If we're running with an accurate clock, chose the BESTSAMPLE
                    200:  * as the estimated offset, otherwise average the remainder.
                    201:  */
                    202: #define        FULLSHIFT       6                       /* NCODES root 2 */
                    203: #define NCODES         (1<< FULLSHIFT)         /* 64 */
                    204: #define        REDUCESHIFT     (FULLSHIFT -1)          /* SAMPLEREDUCE root 2 */
                    205: 
                    206:      /* Towards the high ( Why ?) end of half */
                    207: #define        BESTSAMPLE      ((samplereduce * 3) /4) /* 24 */
                    208: 
                    209:      /* Leap hold time.  After a leap second the clock will no longer be
                    210:  * reliable until it resynchronizes.  Hope 40 minutes is enough. */
                    211: #define        EESLEAPHOLD     (40 * 60)
                    212: 
                    213: #define        EES_STEP_F      (1 << 24) /* the receiver steps in units of about 4ms */
                    214: #define        EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
                    215: #define        EES_STEP_NOTE   (1 << 21)/* Log any unexpected jumps, say .5 ms .... */
                    216: #define        EES_STEP_NOTES  50      /* Only do a limited number */
                    217: #define        MAX_STEP        16      /* Max number of steps to remember */
                    218: 
                    219:      /* debug is a bit mask of debugging that is wanted */
                    220: #define        DB_SYSLOG_SMPLI         0x0001
                    221: #define        DB_SYSLOG_SMPLE         0x0002
                    222: #define        DB_SYSLOG_SMTHI         0x0004
                    223: #define        DB_SYSLOG_NSMTHE        0x0008
                    224: #define        DB_SYSLOG_NSMTHI        0x0010
                    225: #define        DB_SYSLOG_SMTHE         0x0020
                    226: #define        DB_PRINT_EV             0x0040
                    227: #define        DB_PRINT_CDT            0x0080
                    228: #define        DB_PRINT_CDTC           0x0100
                    229: #define        DB_SYSLOG_KEEPD         0x0800
                    230: #define        DB_SYSLOG_KEEPE         0x1000
                    231: #define        DB_LOG_DELTAS           0x2000
                    232: #define        DB_PRINT_DELTAS         0x4000
                    233: #define        DB_LOG_AWAITMORE        0x8000
                    234: #define        DB_LOG_SAMPLES          0x10000
                    235: #define        DB_NO_PPS               0x20000
                    236: #define        DB_INC_PPS              0x40000
                    237: #define        DB_DUMP_DELTAS          0x80000
                    238: 
                    239:      struct eesunit {                  /* EES unit control structure. */
                    240:             struct peer *peer;         /* associated peer structure */
                    241:             struct refclockio io;              /* given to the I/O handler */
                    242:             l_fp       reftime;                /* reference time */
                    243:             l_fp       lastsampletime;         /* time as in txt from last EES msg */
                    244:             l_fp       arrvtime;               /* Time at which pkt arrived */
                    245:             l_fp       codeoffsets[NCODES];    /* the time of arrival of 232 codes */
                    246:             l_fp       offset;                 /* chosen offset        (for clkbug) */
                    247:             l_fp       lowoffset;              /* lowest sample offset (for clkbug) */
                    248:             l_fp       highoffset;             /* highest   "     "    (for clkbug) */
                    249:             char       lastcode[LENEESCODE+6]; /* last time code we received */
                    250:             u_long     lasttime;               /* last time clock heard from */
                    251:             u_long     clocklastgood;          /* last time good radio seen */
                    252:             u_char     lencode;                /* length of code in buffer */
                    253:             u_char     nsamples;               /* number of samples we've collected */
                    254:             u_char     codestate;              /* state of 232 code reception */
                    255:             u_char     unit;                   /* unit number for this guy */
                    256:             u_char     status;                 /* clock status */
                    257:             u_char     lastevent;              /* last clock event */
                    258:             u_char     reason;                 /* reason for last abort */
                    259:             u_char     hour;                   /* hour of day */
                    260:             u_char     minute;                 /* minute of hour */
                    261:             u_char     second;                 /* seconds of minute */
                    262:             char       tz;                     /* timezone from clock */
                    263:             u_char     ttytype;                /* method used */
                    264:             u_char     dump_vals;              /* Should clock values be dumped */
                    265:             u_char     usealldata;             /* Use ALL samples */
                    266:             u_short    day;                    /* day of year from last code */
                    267:             u_long     yearstart;              /* start of current year */
                    268:             u_long     leaphold;               /* time of leap hold expiry */
                    269:             u_long     badformat;              /* number of bad format codes */
                    270:             u_long     baddata;                /* number of invalid time codes */
                    271:             u_long     timestarted;            /* time we started this */
                    272:             long       last_pps_no;            /* The serial # of the last PPS */
                    273:             char       fix_pending;            /* Is a "sync to time" pending ? */
                    274:             /* Fine tuning - compensate for 4 mS ramping .... */
                    275:             l_fp       last_l;                 /* last time stamp */
                    276:             u_char     last_steps[MAX_STEP];   /* Most recent n steps */
                    277:             int        best_av_step;           /* Best guess at average step */
                    278:             char       best_av_step_count;     /* # of steps over used above */
                    279:             char       this_step;              /* Current pos in buffer */
                    280:             int        last_step_late;         /* How late the last step was (0-59) */
                    281:             long       jump_fsecs;             /* # of fractions of a sec last jump */
                    282:             u_long     last_step;              /* time of last step */
                    283:             int        last_step_secs;         /* Number of seconds in last step */
                    284:             int        using_ramp;             /* 1 -> noemal, -1 -> over stepped */
                    285:      };
                    286: #define        last_sec        last_l.l_ui
                    287: #define        last_sfsec      last_l.l_f
                    288: #define        this_uisec      ((ees->arrvtime).l_ui)
                    289: #define        this_sfsec      ((ees->arrvtime).l_f)
                    290: #define        msec(x)         ((x) / (1<<22))
                    291: #define        LAST_STEPS      (sizeof ees->last_steps / sizeof ees->last_steps[0])
                    292: #define        subms(x)        ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
                    293: 
                    294: /* Bitmask for what methods to try to use -- currently only PPS enabled */
                    295: #define        T_CBREAK        1
                    296: #define        T_PPS           8
                    297: /* macros to test above */
                    298: #define        is_cbreak(x)    ((x)->ttytype & T_CBREAK)
                    299: #define        is_pps(x)       ((x)->ttytype & T_PPS)
                    300: #define        is_any(x)       ((x)->ttytype)
                    301: 
                    302: #define        CODEREASON      20      /* reason codes */
                    303: 
                    304: /* Data space for the unit structures.  Note that we allocate these on
                    305:  * the fly, but never give them back. */
                    306: static struct eesunit *eesunits[MAXUNITS];
                    307: static u_char unitinuse[MAXUNITS];
                    308: 
                    309: /* Keep the fudge factors separately so they can be set even
                    310:  * when no clock is configured. */
                    311: static l_fp inherent_delay[MAXUNITS];          /* when time stamp is taken */
                    312: static l_fp fudgefactor[MAXUNITS];             /* fudgetime1 */
                    313: static l_fp os_delay[MAXUNITS];                        /* fudgetime2 */
                    314: static l_fp offset_fudge[MAXUNITS];            /* Sum of above */
                    315: static u_char stratumtouse[MAXUNITS];
                    316: static u_char sloppyclockflag[MAXUNITS];
                    317: 
                    318: static int deltas[60];
                    319: 
                    320: static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
                    321: static l_fp onesec; /* = { 1, 0 }; */
                    322: 
                    323: #ifndef        DUMP_BUF_SIZE   /* Size of buffer to be used by dump_buf */
                    324: #define        DUMP_BUF_SIZE   10112
                    325: #endif
                    326: 
                    327: /* ees_reset - reset the count back to zero */
                    328: #define        ees_reset(ees) (ees)->nsamples = 0; \
                    329: (ees)->codestate = EESCS_WAIT
                    330: 
                    331: /* ees_event - record and report an event */
                    332: #define        ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
                    333: ees_report_event((ees), (evcode))
                    334: 
                    335:      /* Find the precision of the system clock by reading it */
                    336: #define        USECS   1000000
                    337: #define        MINSTEP 5       /* some systems increment uS on each call */
                    338: #define        MAXLOOPS (USECS/9)
                    339: 
                    340: /*
                    341:  * Function prototypes
                    342:  */
                    343: 
                    344: static int     msfees_start    P((int unit, struct peer *peer));
                    345: static void    msfees_shutdown P((int unit, struct peer *peer));
                    346: static void    msfees_poll     P((int unit, struct peer *peer));
                    347: static void    msfees_init     P((void));
                    348: static void    dump_buf        P((l_fp *coffs, int from, int to, char *text));
                    349: static void    ees_report_event P((struct eesunit *ees, int code));
                    350: static void    ees_receive     P((struct recvbuf *rbufp));
                    351: static void    ees_process     P((struct eesunit *ees));
                    352: #ifdef QSORT_USES_VOID_P
                    353: static int     offcompare      P((const void *va, const void *vb));
                    354: #else
                    355: static int     offcompare      P((const l_fp *a, const l_fp *b));
                    356: #endif /* QSORT_USES_VOID_P */
                    357: 
                    358: 
                    359: /*
                    360:  * Transfer vector
                    361:  */
                    362: struct refclock refclock_msfees = {
                    363:        msfees_start,           /* start up driver */
                    364:        msfees_shutdown,        /* shut down driver */
                    365:        msfees_poll,            /* transmit poll message */
                    366:        noentry,                /* not used */
                    367:        msfees_init,            /* initialize driver */
                    368:        noentry,                /* not used */
                    369:        NOFLAGS                 /* not used */
                    370: };
                    371: 
                    372: 
                    373: static void
                    374: dump_buf(
                    375:        l_fp *coffs,
                    376:        int from,
                    377:        int to,
                    378:        char *text
                    379:        )
                    380: {
                    381:        char buff[DUMP_BUF_SIZE + 80];
                    382:        int i;
                    383:        register char *ptr = buff;
                    384: 
                    385:        snprintf(buff, sizeof(buff), text);
                    386:        for (i = from; i < to; i++) {
                    387:                ptr += strlen(ptr);
                    388:                if ((ptr - buff) > DUMP_BUF_SIZE) {
                    389:                        msyslog(LOG_DEBUG, "D: %s", buff);
                    390:                        ptr = buff;
                    391:                }
                    392:                snprintf(ptr, sizeof(buff) - (ptr - buff),
                    393:                         " %06d", ((int)coffs[i].l_f) / 4295);
                    394:        }
                    395:        msyslog(LOG_DEBUG, "D: %s", buff);
                    396: }
                    397: 
                    398: /* msfees_init - initialize internal ees driver data */
                    399: static void
                    400: msfees_init(void)
                    401: {
                    402:        register int i;
                    403:        /* Just zero the data arrays */
                    404:        memset((char *)eesunits, 0, sizeof eesunits);
                    405:        memset((char *)unitinuse, 0, sizeof unitinuse);
                    406: 
                    407:        acceptable_slop.l_ui = 0;
                    408:        acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
                    409: 
                    410:        onesec.l_ui = 1;
                    411:        onesec.l_uf = 0;
                    412: 
                    413:        /* Initialize fudge factors to default. */
                    414:        for (i = 0; i < MAXUNITS; i++) {
                    415:                fudgefactor[i].l_ui     = 0;
                    416:                fudgefactor[i].l_uf     = DEFFUDGETIME;
                    417:                os_delay[i].l_ui        = 0;
                    418:                os_delay[i].l_uf        = DEFOSTIME;
                    419:                inherent_delay[i].l_ui  = 0;
                    420:                inherent_delay[i].l_uf  = DEFINHTIME;
                    421:                offset_fudge[i]         = os_delay[i];
                    422:                L_ADD(&offset_fudge[i], &fudgefactor[i]);
                    423:                L_ADD(&offset_fudge[i], &inherent_delay[i]);
                    424:                stratumtouse[i]         = 0;
                    425:                sloppyclockflag[i]      = 0;
                    426:        }
                    427: }
                    428: 
                    429: 
                    430: /* msfees_start - open the EES devices and initialize data for processing */
                    431: static int
                    432: msfees_start(
                    433:        int unit,
                    434:        struct peer *peer
                    435:        )
                    436: {
                    437:        register struct eesunit *ees;
                    438:        register int i;
                    439:        int fd232 = -1;
                    440:        char eesdev[20];
                    441:        struct termios ttyb, *ttyp;
                    442:        struct refclockproc *pp;
                    443:        pp = peer->procptr;
                    444: 
                    445:        if (unit >= MAXUNITS) {
                    446:                msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
                    447:                        unit, MAXUNITS-1);
                    448:                return 0;
                    449:        }
                    450:        if (unitinuse[unit]) {
                    451:                msyslog(LOG_ERR, "ees clock: unit number %d in use", unit);
                    452:                return 0;
                    453:        }
                    454: 
                    455:        /* Unit okay, attempt to open the devices.  We do them both at
                    456:         * once to make sure we can */
                    457:        snprintf(eesdev, sizeof(eesdev), EES232, unit);
                    458: 
                    459:        fd232 = open(eesdev, O_RDWR, 0777);
                    460:        if (fd232 == -1) {
                    461:                msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
                    462:                return 0;
                    463:        }
                    464: 
                    465: #ifdef TIOCEXCL
                    466:        /* Set for exclusive use */
                    467:        if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
                    468:                msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
                    469:                goto screwed;
                    470:        }
                    471: #endif
                    472: 
                    473:        /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
                    474: 
                    475:        /* Set port characteristics.  If we don't have a STREAMS module or
                    476:         * a clock line discipline, cooked mode is just usable, even though it
                    477:         * strips the top bit.  The only EES byte which uses the top
                    478:         * bit is the year, and we don't use that anyway. If we do
                    479:         * have the line discipline, we choose raw mode, and the
                    480:         * line discipline code will block up the messages.
                    481:         */
                    482: 
                    483:        /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
                    484: 
                    485:        ttyp = &ttyb;
                    486:        if (tcgetattr(fd232, ttyp) < 0) {
                    487:                msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
                    488:                goto screwed;
                    489:        }
                    490: 
                    491:        ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
                    492:        ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
                    493:        ttyp->c_oflag = 0;
                    494:        ttyp->c_lflag = ICANON;
                    495:        ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
                    496:        if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
                    497:                msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
                    498:                goto screwed;
                    499:        }
                    500: 
                    501:        if (tcflush(fd232, TCIOFLUSH) < 0) {
                    502:                msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
                    503:                goto screwed;
                    504:        }
                    505: 
                    506:        inherent_delay[unit].l_uf = INH_DELAY_PPS;
                    507: 
                    508:        /* offset fudge (how *late* the timestamp is) = fudge + os delays */
                    509:        offset_fudge[unit] = os_delay[unit];
                    510:        L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
                    511:        L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
                    512: 
                    513:        /* Looks like this might succeed.  Find memory for the structure.
                    514:         * Look to see if there are any unused ones, if not we malloc() one.
                    515:         */
                    516:        if (eesunits[unit] != 0) /* The one we want is okay */
                    517:            ees = eesunits[unit];
                    518:        else {
                    519:                /* Look for an unused, but allocated struct */
                    520:                for (i = 0; i < MAXUNITS; i++) {
                    521:                        if (!unitinuse[i] && eesunits[i] != 0)
                    522:                            break;
                    523:                }
                    524: 
                    525:                if (i < MAXUNITS) {     /* Reclaim this one */
                    526:                        ees = eesunits[i];
                    527:                        eesunits[i] = 0;
                    528:                }                       /* no spare -- make a new one */
                    529:                else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
                    530:        }
                    531:        memset((char *)ees, 0, sizeof(struct eesunit));
                    532:        eesunits[unit] = ees;
                    533: 
                    534:        /* Set up the structures */
                    535:        ees->peer       = peer;
                    536:        ees->unit       = (u_char)unit;
                    537:        ees->timestarted= current_time;
                    538:        ees->ttytype    = 0;
                    539:        ees->io.clock_recv= ees_receive;
                    540:        ees->io.srcclock= (caddr_t)ees;
                    541:        ees->io.datalen = 0;
                    542:        ees->io.fd      = fd232;
                    543: 
                    544:        /* Okay.  Push one of the two (linked into the kernel, or dynamically
                    545:         * loaded) STREAMS module, and give it to the I/O code to start
                    546:         * receiving stuff.
                    547:         */
                    548: 
                    549: #ifdef STREAM
                    550:        {
                    551:                int rc1;
                    552:                /* Pop any existing onews first ... */
                    553:                while (ioctl(fd232, I_POP, 0 ) >= 0) ;
                    554: 
                    555:                /* Now try pushing either of the possible modules */
                    556:                if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
                    557:                    ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
                    558:                        msyslog(LOG_ERR,
                    559:                                "ees clock: Push of `%s' and `%s' to %s failed %m",
                    560:                                STREAM_PP1, STREAM_PP2, eesdev);
                    561:                        goto screwed;
                    562:                }
                    563:                else {
                    564:                        NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                    565:                                msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
                    566:                                        (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
                    567:                        ees->ttytype |= T_PPS;
                    568:                }
                    569:        }
                    570: #endif /* STREAM */
                    571: 
                    572:        /* Add the clock */
                    573:        if (!io_addclock(&ees->io)) {
                    574:                /* Oh shit.  Just close and return. */
                    575:                msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
                    576:                goto screwed;
                    577:        }
                    578: 
                    579: 
                    580:        /* All done.  Initialize a few random peer variables, then
                    581:         * return success. */
                    582:        peer->precision = sys_precision;
                    583:        peer->stratum   = stratumtouse[unit];
                    584:        if (stratumtouse[unit] <= 1) {
                    585:                memcpy((char *)&pp->refid, EESREFID, 4);
                    586:                if (unit > 0 && unit < 10)
                    587:                    ((char *)&pp->refid)[3] = '0' + unit;
                    588:        } else {
                    589:                peer->refid = htonl(EESHSREFID);
                    590:        }
                    591:        unitinuse[unit] = 1;
                    592:        pp->unitptr = (caddr_t) &eesunits[unit];
                    593:        pp->clockdesc = EESDESCRIPTION;
                    594:        msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
                    595:        return (1);
                    596: 
                    597:     screwed:
                    598:        if (fd232 != -1)
                    599:            (void) close(fd232);
                    600:        return (0);
                    601: }
                    602: 
                    603: 
                    604: /* msfees_shutdown - shut down a EES clock */
                    605: static void
                    606: msfees_shutdown(
                    607:        int unit,
                    608:        struct peer *peer
                    609:        )
                    610: {
                    611:        register struct eesunit *ees;
                    612: 
                    613:        if (unit >= MAXUNITS) {
                    614:                msyslog(LOG_ERR,
                    615:                        "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
                    616:                        unit, MAXUNITS);
                    617:                return;
                    618:        }
                    619:        if (!unitinuse[unit]) {
                    620:                msyslog(LOG_ERR,
                    621:                        "ees clock: INTERNAL ERROR, unit number %d not in use", unit);
                    622:                return;
                    623:        }
                    624: 
                    625:        /* Tell the I/O module to turn us off.  We're history. */
                    626:        ees = eesunits[unit];
                    627:        io_closeclock(&ees->io);
                    628:        unitinuse[unit] = 0;
                    629: }
                    630: 
                    631: 
                    632: /* ees_report_event - note the occurance of an event */
                    633: static void
                    634: ees_report_event(
                    635:        struct eesunit *ees,
                    636:        int code
                    637:        )
                    638: {
                    639:        if (ees->status != (u_char)code) {
                    640:                ees->status = (u_char)code;
                    641:                if (code != CEVNT_NOMINAL)
                    642:                    ees->lastevent = (u_char)code;
                    643:                /* Should report event to trap handler in here.
                    644:                 * Soon...
                    645:                 */
                    646:        }
                    647: }
                    648: 
                    649: 
                    650: /* ees_receive - receive data from the serial interface on an EES clock */
                    651: static void
                    652: ees_receive(
                    653:        struct recvbuf *rbufp
                    654:        )
                    655: {
                    656:        register int n_sample;
                    657:        register int day;
                    658:        register struct eesunit *ees;
                    659:        register u_char *dpt;           /* Data PoinTeR: move along ... */
                    660:        register u_char *dpend;         /* Points just *after* last data char */
                    661:        register char *cp;
                    662:        l_fp tmp;
                    663:        int call_pps_sample = 0;
                    664:        l_fp pps_arrvstamp;
                    665:        int     sincelast;
                    666:        int     pps_step = 0;
                    667:        int     suspect_4ms_step = 0;
                    668:        struct ppsclockev ppsclockev;
                    669:        long *ptr = (long *) &ppsclockev;
                    670:        int rc;
                    671:        int request;
                    672: #ifdef HAVE_CIOGETEV
                    673:        request = CIOGETEV;
                    674: #endif
                    675: #ifdef HAVE_TIOCGPPSEV
                    676:        request = TIOCGPPSEV;
                    677: #endif
                    678: 
                    679:        /* Get the clock this applies to and a pointer to the data */
                    680:        ees = (struct eesunit *)rbufp->recv_srcclock;
                    681:        dpt = (u_char *)&rbufp->recv_space;
                    682:        dpend = dpt + rbufp->recv_length;
                    683:        if ((dbg & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
                    684:            printf("[%d] ", rbufp->recv_length);
                    685: 
                    686:        /* Check out our state and process appropriately */
                    687:        switch (ees->codestate) {
                    688:            case EESCS_WAIT:
                    689:                /* Set an initial guess at the timestamp as the recv time.
                    690:                 * If just running in CBREAK mode, we can't improve this.
                    691:                 * If we have the CLOCK Line Discipline, PPSCD, or sime such,
                    692:                 * then we will do better later ....
                    693:                 */
                    694:                ees->arrvtime = rbufp->recv_time;
                    695:                ees->codestate = EESCS_GOTSOME;
                    696:                ees->lencode = 0;
                    697:                /*FALLSTHROUGH*/
                    698: 
                    699:            case EESCS_GOTSOME:
                    700:                cp = &(ees->lastcode[ees->lencode]);
                    701: 
                    702:                /* Gobble the bytes until the final (possibly stripped) 0xff */
                    703:                while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
                    704:                        *cp++ = (char)*dpt++;
                    705:                        ees->lencode++;
                    706:                        /* Oh dear -- too many bytes .. */
                    707:                        if (ees->lencode > LENEESPRT) {
                    708:                                NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                    709:                                        msyslog(LOG_INFO,
                    710:                                                "I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
                    711:                                                ees->lencode, dpend - dpt, LENEESPRT,
                    712: #define D(x) (ees->lastcode[x])
                    713:                                                D(0), D(1), D(2), D(3), D(4), D(5), D(6),
                    714:                                                D(7), D(8), D(9), D(10), D(11), D(12));
                    715: #undef D
                    716:                                ees->badformat++;
                    717:                                ees->reason = CODEREASON + 1;
                    718:                                ees_event(ees, CEVNT_BADREPLY);
                    719:                                ees_reset(ees);
                    720:                                return;
                    721:                        }
                    722:                }
                    723:                /* Gave up because it was end of the buffer, rather than ff */
                    724:                if (dpt == dpend) {
                    725:                        /* Incomplete.  Wait for more. */
                    726:                        if (dbg & DB_LOG_AWAITMORE)
                    727:                            msyslog(LOG_INFO,
                    728:                                    "I: ees clock %d: %p == %p: await more",
                    729:                                    ees->unit, dpt, dpend);
                    730:                        return;
                    731:                }
                    732: 
                    733:                /* This shouldn't happen ... ! */
                    734:                if ((*dpt & 0x7f) != 0x7f) {
                    735:                        msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
                    736:                        ees->badformat++;
                    737:                        ees->reason = CODEREASON + 2;
                    738:                        ees_event(ees, CEVNT_BADREPLY);
                    739:                        ees_reset(ees);
                    740:                        return;
                    741:                }
                    742: 
                    743:                /* Skip the 0xff */
                    744:                dpt++;
                    745: 
                    746:                /* Finally, got a complete buffer.  Mainline code will
                    747:                 * continue on. */
                    748:                cp = ees->lastcode;
                    749:                break;
                    750: 
                    751:            default:
                    752:                msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
                    753:                        ees->unit, ees->codestate);
                    754:                ees->reason = CODEREASON + 5;
                    755:                ees_event(ees, CEVNT_FAULT);
                    756:                ees_reset(ees);
                    757:                return;
                    758:        }
                    759: 
                    760:        /* Boy!  After all that crap, the lastcode buffer now contains
                    761:         * something we hope will be a valid time code.  Do length
                    762:         * checks and sanity checks on constant data.
                    763:         */
                    764:        ees->codestate = EESCS_WAIT;
                    765:        ees->lasttime = current_time;
                    766:        if (ees->lencode != LENEESPRT) {
                    767:                ees->badformat++;
                    768:                ees->reason = CODEREASON + 6;
                    769:                ees_event(ees, CEVNT_BADREPLY);
                    770:                ees_reset(ees);
                    771:                return;
                    772:        }
                    773: 
                    774:        cp = ees->lastcode;
                    775: 
                    776:        /* Check that centisecond is zero */
                    777:        if (cp[EESM_CSEC] != 0) {
                    778:                ees->baddata++;
                    779:                ees->reason = CODEREASON + 7;
                    780:                ees_event(ees, CEVNT_BADREPLY);
                    781:                ees_reset(ees);
                    782:                return;
                    783:        }
                    784: 
                    785:        /* Check flag formats */
                    786:        if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
                    787:                ees->badformat++;
                    788:                ees->reason = CODEREASON + 8;
                    789:                ees_event(ees, CEVNT_BADREPLY);
                    790:                ees_reset(ees);
                    791:                return;
                    792:        }
                    793: 
                    794:        if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
                    795:                ees->badformat++;
                    796:                ees->reason = CODEREASON + 9;
                    797:                ees_event(ees, CEVNT_BADREPLY);
                    798:                ees_reset(ees);
                    799:                return;
                    800:        }
                    801: 
                    802:        if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
                    803:                ees->badformat++;
                    804:                ees->reason = CODEREASON + 10;
                    805:                ees_event(ees, CEVNT_BADREPLY);
                    806:                ees_reset(ees);
                    807:                return;
                    808:        }
                    809: 
                    810:        /* So far, so good.  Compute day, hours, minutes, seconds,
                    811:         * time zone.  Do range checks on these.
                    812:         */
                    813: 
                    814: #define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
                    815: #define istrue(x)      ((x)?1:0)
                    816: 
                    817:        ees->second  = bcdunpack(cp[EESM_SEC]);  /* second       */
                    818:        ees->minute  = bcdunpack(cp[EESM_MIN]);  /* minute       */
                    819:        ees->hour    = bcdunpack(cp[EESM_HOUR]); /* hour         */
                    820: 
                    821:        day          = bcdunpack(cp[EESM_DAY]);  /* day of month */
                    822: 
                    823:        switch (bcdunpack(cp[EESM_MON])) {       /* month        */
                    824: 
                    825:                /*  Add in lengths of all previous months.  Add one more
                    826:                    if it is a leap year and after February.
                    827:                */
                    828:            case 12:    day += NOV;                       /*FALLSTHROUGH*/
                    829:            case 11:    day += OCT;                       /*FALLSTHROUGH*/
                    830:            case 10:    day += SEP;                       /*FALLSTHROUGH*/
                    831:            case  9:    day += AUG;                       /*FALLSTHROUGH*/
                    832:            case  8:    day += JUL;                       /*FALLSTHROUGH*/
                    833:            case  7:    day += JUN;                       /*FALLSTHROUGH*/
                    834:            case  6:    day += MAY;                       /*FALLSTHROUGH*/
                    835:            case  5:    day += APR;                       /*FALLSTHROUGH*/
                    836:            case  4:    day += MAR;                       /*FALLSTHROUGH*/
                    837:            case  3:    day += FEB;
                    838:                if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
                    839:            case  2:    day += JAN;                       /*FALLSTHROUGH*/
                    840:            case  1:    break;
                    841:            default:    ees->baddata++;
                    842:                ees->reason = CODEREASON + 11;
                    843:                ees_event(ees, CEVNT_BADDATE);
                    844:                ees_reset(ees);
                    845:                return;
                    846:        }
                    847: 
                    848:        ees->day     = day;
                    849: 
                    850:        /* Get timezone. The clocktime routine wants the number
                    851:         * of hours to add to the delivered time to get UT.
                    852:         * Currently -1 if BST flag set, 0 otherwise.  This
                    853:         * is the place to tweak things if double summer time
                    854:         * ever happens.
                    855:         */
                    856:        ees->tz      = istrue(cp[EESM_BST]) ? -1 : 0;
                    857: 
                    858:        if (ees->day > 366 || ees->day < 1 ||
                    859:            ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
                    860:                ees->baddata++;
                    861:                ees->reason = CODEREASON + 12;
                    862:                ees_event(ees, CEVNT_BADDATE);
                    863:                ees_reset(ees);
                    864:                return;
                    865:        }
                    866: 
                    867:        n_sample = ees->nsamples;
                    868: 
                    869:        /* Now, compute the reference time value: text -> tmp.l_ui */
                    870:        if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
                    871:                       ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
                    872:                       &tmp.l_ui)) {
                    873:                ees->baddata++;
                    874:                ees->reason = CODEREASON + 13;
                    875:                ees_event(ees, CEVNT_BADDATE);
                    876:                ees_reset(ees);
                    877:                return;
                    878:        }
                    879:        tmp.l_uf = 0;
                    880: 
                    881:        /*  DON'T use ees->arrvtime -- it may be < reftime */
                    882:        ees->lastsampletime = tmp;
                    883: 
                    884:        /* If we are synchronised to the radio, update the reference time.
                    885:         * Also keep a note of when clock was last good.
                    886:         */
                    887:        if (istrue(cp[EESM_MSFOK])) {
                    888:                ees->reftime = tmp;
                    889:                ees->clocklastgood = current_time;
                    890:        }
                    891: 
                    892: 
                    893:        /* Compute the offset.  For the fractional part of the
                    894:         * offset we use the expected delay for the message.
                    895:         */
                    896:        ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
                    897:        ees->codeoffsets[n_sample].l_uf = 0;
                    898: 
                    899:        /* Number of seconds since the last step */
                    900:        sincelast = this_uisec - ees->last_step;
                    901: 
                    902:        memset((char *) &ppsclockev, 0, sizeof ppsclockev);
                    903: 
                    904:        rc = ioctl(ees->io.fd, request, (char *) &ppsclockev);
                    905:        if (dbg & DB_PRINT_EV) fprintf(stderr,
                    906:                                         "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n",
                    907:                                         DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees),
                    908:                                         rc, errno, ptr[0], ptr[1], ptr[2]);
                    909: 
                    910:        /* If we managed to get the time of arrival, process the info */
                    911:        if (rc >= 0) {
                    912:                int conv = -1;
                    913:                pps_step = ppsclockev.serial - ees->last_pps_no;
                    914: 
                    915:                /* Possible that PPS triggered, but text message didn't */
                    916:                if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
                    917:                if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
                    918:                if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
                    919: 
                    920:                /* allow for single loss of PPS only */
                    921:                if (pps_step != 1 && pps_step != 2)
                    922:                    fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
                    923:                            ppsclockev.serial, ees->last_pps_no, pps_step);
                    924:                else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
                    925:                    fprintf(stderr, "buftvtots failed\n");
                    926:                else {  /* if ((ABS(time difference) - 0.25) < 0)
                    927:                         * then believe it ...
                    928:                         */
                    929:                        l_fp diff;
                    930:                        diff = pps_arrvstamp;
                    931:                        conv = 0;
                    932:                        L_SUB(&diff, &ees->arrvtime);
                    933:                        if (dbg & DB_PRINT_CDT)
                    934:                            printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s",
                    935:                                   DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf,
                    936:                                   (long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf,
                    937:                                   (long)diff.l_ui, (long)diff.l_uf,
                    938:                                   ctime(&(ppsclockev.tv.tv_sec)));
                    939:                        if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
                    940:                        L_SUB(&diff, &acceptable_slop);
                    941:                        if (L_ISNEG(&diff)) {   /* AOK -- pps_sample */
                    942:                                ees->arrvtime = pps_arrvstamp;
                    943:                                conv++;
                    944:                                call_pps_sample++;
                    945:                        }
                    946:                        /* Some loss of some signals around sec = 1 */
                    947:                        else if (ees->second == 1) {
                    948:                                diff = pps_arrvstamp;
                    949:                                L_ADD(&diff, &onesec);
                    950:                                L_SUB(&diff, &ees->arrvtime);
                    951:                                if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
                    952:                                L_SUB(&diff, &acceptable_slop);
                    953:                                msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
                    954:                                        pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
                    955:                                        pps_arrvstamp.l_uf,
                    956:                                        ees->arrvtime.l_uf,
                    957:                                        diff.l_ui, diff.l_uf,
                    958:                                        (int)ppsclockev.tv.tv_usec,
                    959:                                        ctime(&(ppsclockev.tv.tv_sec)));
                    960:                                if (L_ISNEG(&diff)) {   /* AOK -- pps_sample */
                    961:                                        suspect_4ms_step |= 2;
                    962:                                        ees->arrvtime = pps_arrvstamp;
                    963:                                        L_ADD(&ees->arrvtime, &onesec);
                    964:                                        conv++;
                    965:                                        call_pps_sample++;
                    966:                                }
                    967:                        }
                    968:                }
                    969:                ees->last_pps_no = ppsclockev.serial;
                    970:                if (dbg & DB_PRINT_CDTC)
                    971:                    printf(
                    972:                            "[%x] %08lx %08lx %d u%d (%d %d)\n",
                    973:                            DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui,
                    974:                            (long)pps_arrvstamp.l_uf, conv, ees->unit,
                    975:                            call_pps_sample, pps_step);
                    976:        }
                    977: 
                    978:        /* See if there has been a 4ms jump at a minute boundry */
                    979:        {       l_fp    delta;
                    980: #define        delta_isec      delta.l_ui
                    981: #define        delta_ssec      delta.l_i
                    982: #define        delta_sfsec     delta.l_f
                    983:        long    delta_f_abs;
                    984: 
                    985:        delta.l_i = ees->arrvtime.l_i;
                    986:        delta.l_f = ees->arrvtime.l_f;
                    987: 
                    988:        L_SUB(&delta, &ees->last_l);
                    989:        delta_f_abs = delta_sfsec;
                    990:        if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
                    991: 
                    992:        /* Dump the deltas each minute */
                    993:        if (dbg & DB_DUMP_DELTAS)
                    994:        {       
                    995:                if (/*0 <= ees->second && */
                    996:                    ees->second < COUNTOF(deltas))
                    997:                        deltas[ees->second] = delta_sfsec;
                    998:        /* Dump on second 1, as second 0 sometimes missed */
                    999:        if (ees->second == 1) {
                   1000:                char text[16 * COUNTOF(deltas)];
                   1001:                char *cptr=text;
                   1002:                int i;
                   1003:                for (i = 0; i < COUNTOF(deltas); i++) {
                   1004:                        snprintf(cptr, sizeof(text) / COUNTOF(deltas),
                   1005:                                " %d.%04d", msec(deltas[i]),
                   1006:                                subms(deltas[i]));
                   1007:                        cptr += strlen(cptr);
                   1008:                }
                   1009:                msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
                   1010:                        msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
                   1011:                        msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
                   1012:                        text+1);
                   1013:                for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
                   1014:        }
                   1015:        }
                   1016: 
                   1017:        /* Lets see if we have a 4 mS step at a minute boundaary */
                   1018:        if (    ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
                   1019:                (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
                   1020:                (ees->second == 0 || ees->second == 1 || ees->second == 2) &&
                   1021:                (sincelast < 0 || sincelast > 122)
                   1022:                ) {     /* 4ms jump at min boundry */
                   1023:                int old_sincelast;
                   1024:                int count=0;
                   1025:                int sum = 0;
                   1026:                /* Yes -- so compute the ramp time */
                   1027:                if (ees->last_step == 0) sincelast = 0;
                   1028:                old_sincelast = sincelast;
                   1029: 
                   1030:                /* First time in, just set "ees->last_step" */
                   1031:                if(ees->last_step) {
                   1032:                        int other_step = 0;
                   1033:                        int third_step = 0;
                   1034:                        int this_step = (sincelast + (60 /2)) / 60;
                   1035:                        int p_step = ees->this_step;
                   1036:                        int p;
                   1037:                        ees->last_steps[p_step] = this_step;
                   1038:                        p= p_step;
                   1039:                        p_step++;
                   1040:                        if (p_step >= LAST_STEPS) p_step = 0;
                   1041:                        ees->this_step = p_step;
                   1042:                                /* Find the "average" interval */
                   1043:                        while (p != p_step) {
                   1044:                                int this = ees->last_steps[p];
                   1045:                                if (this == 0) break;
                   1046:                                if (this != this_step) {
                   1047:                                        if (other_step == 0 && (
                   1048:                                                this== (this_step +2) ||
                   1049:                                                this== (this_step -2) ||
                   1050:                                                this== (this_step +1) ||
                   1051:                                                this== (this_step -1)))
                   1052:                                            other_step = this;
                   1053:                                        if (other_step != this) {
                   1054:                                                int idelta = (this_step - other_step);
                   1055:                                                if (idelta < 0) idelta = - idelta;
                   1056:                                                if (third_step == 0 && (
                   1057:                                                        (idelta == 1) ? (
                   1058:                                                                this == (other_step +1) ||
                   1059:                                                                this == (other_step -1) ||
                   1060:                                                                this == (this_step +1) ||
                   1061:                                                                this == (this_step -1))
                   1062:                                                        :
                   1063:                                                        (
                   1064:                                                                this == (this_step + other_step)/2
                   1065:                                                                )
                   1066:                                                        )) third_step = this;
                   1067:                                                if (third_step != this) break;
                   1068:                                        }
                   1069:                                }
                   1070:                                sum += this;
                   1071:                                p--;
                   1072:                                if (p < 0) p += LAST_STEPS;
                   1073:                                count++;
                   1074:                        }
                   1075:                        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);
                   1076:                        if (count != 0) sum = ((sum * 60) + (count /2)) / count;
                   1077: #define        SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
                   1078:                        msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                   1079:                                ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
                   1080:                                SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
                   1081:                        printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
                   1082:                               ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
                   1083:                               SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
                   1084: #undef SV
                   1085:                        ees->jump_fsecs = delta_sfsec;
                   1086:                        ees->using_ramp = 1;
                   1087:                        if (sincelast > 170)
                   1088:                            ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
                   1089:                        else ees->last_step_late = 30;
                   1090:                        if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
                   1091:                        if (ees->last_step_late < 0) ees->last_step_late = 0;
                   1092:                        if (ees->last_step_late >= 60) ees->last_step_late = 59;
                   1093:                        sincelast = 0;
                   1094:                }
                   1095:                else {  /* First time in -- just save info */
                   1096:                        ees->last_step_late = 30;
                   1097:                        ees->jump_fsecs = delta_sfsec;
                   1098:                        ees->using_ramp = 1;
                   1099:                        sum = 4 * 60;
                   1100:                }
                   1101:                ees->last_step = this_uisec;
                   1102:                printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n",
                   1103:                       ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
                   1104:                       ees->second, old_sincelast, ees->last_step_late, count, sum,
                   1105:                       ees->last_step_secs);
                   1106:                msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
                   1107:                        ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second,
                   1108:                        old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
                   1109:                if (sum) ees->last_step_secs = sum;
                   1110:        }
                   1111:        /* OK, so not a 4ms step at a minute boundry */
                   1112:        else {
                   1113:                if (suspect_4ms_step) msyslog(LOG_ERR,
                   1114:                                              "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
                   1115:                                              ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
                   1116:                                              msec(EES_STEP_F - EES_STEP_F_GRACE),
                   1117:                                              subms(EES_STEP_F - EES_STEP_F_GRACE),
                   1118:                                              (int)msec(delta_f_abs),
                   1119:                                              (int)subms(delta_f_abs),
                   1120:                                              msec(EES_STEP_F + EES_STEP_F_GRACE),
                   1121:                                              subms(EES_STEP_F + EES_STEP_F_GRACE),
                   1122:                                              ees->second,
                   1123:                                              sincelast);
                   1124:                if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
                   1125:                        static int ees_step_notes = EES_STEP_NOTES;
                   1126:                        if (ees_step_notes > 0) {
                   1127:                                ees_step_notes--;
                   1128:                                printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n",
                   1129:                                       ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
                   1130:                                       ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
                   1131:                                msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
                   1132:                                        ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
                   1133:                        }
                   1134:                }
                   1135:        }
                   1136:        }
                   1137:        ees->last_l = ees->arrvtime;
                   1138: 
                   1139:        /* IF we have found that it's ramping
                   1140:         * && it's within twice the expected ramp period
                   1141:         * && there is a non zero step size (avoid /0 !)
                   1142:         * THEN we twiddle things
                   1143:         */
                   1144:        if (ees->using_ramp &&
                   1145:            sincelast < (ees->last_step_secs)*2 &&
                   1146:            ees->last_step_secs)
                   1147:        {       long    sec_of_ramp = sincelast + ees->last_step_late;
                   1148:        long    fsecs;
                   1149:        l_fp    inc;
                   1150: 
                   1151:        /* Ramp time may vary, so may ramp for longer than last time */
                   1152:        if (sec_of_ramp > (ees->last_step_secs + 120))
                   1153:            sec_of_ramp =  ees->last_step_secs;
                   1154: 
                   1155:        /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
                   1156:        fsecs = sec_of_ramp * (ees->jump_fsecs /  ees->last_step_secs);
                   1157: 
                   1158:        if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
                   1159:                                           "[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)",
                   1160:                                           DB_LOG_DELTAS,
                   1161:                                           ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
                   1162:                                           pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
                   1163:        if (dbg & DB_PRINT_DELTAS) printf(
                   1164:                "MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n",
                   1165:                ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
                   1166:                (long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
                   1167: 
                   1168:        /* Must sign extend the result */
                   1169:        inc.l_i = (fsecs < 0) ? -1 : 0;
                   1170:        inc.l_f = fsecs;
                   1171:        if (dbg & DB_INC_PPS)
                   1172:        {       L_SUB(&pps_arrvstamp, &inc);
                   1173:        L_SUB(&ees->arrvtime, &inc);
                   1174:        }
                   1175:        else
                   1176:        {       L_ADD(&pps_arrvstamp, &inc);
                   1177:        L_ADD(&ees->arrvtime, &inc);
                   1178:        }
                   1179:        }
                   1180:        else {
                   1181:                if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
                   1182:                                                   "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
                   1183:                                                   DB_LOG_DELTAS,
                   1184:                                                   ees->unit, ees->using_ramp,
                   1185:                                                   sincelast,
                   1186:                                                   (ees->last_step_secs)*2,
                   1187:                                                   ees->last_step_secs);
                   1188:                if (dbg & DB_PRINT_DELTAS) printf(
                   1189:                        "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
                   1190:                        DB_LOG_DELTAS,
                   1191:                        ees->unit, ees->using_ramp,
                   1192:                        sincelast,
                   1193:                        (ees->last_step_secs)*2,
                   1194:                        ees->last_step_secs);
                   1195:        }
                   1196: 
                   1197:        L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
                   1198:        L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
                   1199: 
                   1200:        if (call_pps_sample && !(dbg & DB_NO_PPS)) {
                   1201:                /* Sigh -- it expects its args negated */
                   1202:                L_NEG(&pps_arrvstamp);
                   1203:                /*
                   1204:                 * I had to disable this here, since it appears there is no pointer to the
                   1205:                 * peer structure.
                   1206:                 *
                   1207:                 (void) pps_sample(peer, &pps_arrvstamp);
                   1208:                */
                   1209:        }
                   1210: 
                   1211:        /* Subtract off the local clock time stamp */
                   1212:        L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
                   1213:        if (dbg & DB_LOG_SAMPLES) msyslog(LOG_ERR,
                   1214:                                            "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
                   1215:                                            ees->unit, DB_LOG_DELTAS, n_sample,
                   1216:                                            ees->codeoffsets[n_sample].l_f,
                   1217:                                            ees->codeoffsets[n_sample].l_f / 4295,
                   1218:                                            pps_arrvstamp.l_f,
                   1219:                                            pps_arrvstamp.l_f /4295,
                   1220:                                            (dbg & DB_NO_PPS) ? " [no PPS]" : "");
                   1221: 
                   1222:        if (ees->nsamples++ == NCODES-1) ees_process(ees);
                   1223: 
                   1224:        /* Done! */
                   1225: }
                   1226: 
                   1227: 
                   1228: /* offcompare - auxiliary comparison routine for offset sort */
                   1229: 
                   1230: #ifdef QSORT_USES_VOID_P
                   1231: static int
                   1232: offcompare(
                   1233:        const void *va,
                   1234:        const void *vb
                   1235:        )
                   1236: {
                   1237:        const l_fp *a = (const l_fp *)va;
                   1238:        const l_fp *b = (const l_fp *)vb;
                   1239:        return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
                   1240: }
                   1241: #else
                   1242: static int
                   1243: offcompare(
                   1244:        const l_fp *a,
                   1245:        const l_fp *b
                   1246:        )
                   1247: {
                   1248:        return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
                   1249: }
                   1250: #endif /* QSORT_USES_VOID_P */
                   1251: 
                   1252: 
                   1253: /* ees_process - process a pile of samples from the clock */
                   1254: static void
                   1255: ees_process(
                   1256:        struct eesunit *ees
                   1257:        )
                   1258: {
                   1259:        static int last_samples = -1;
                   1260:        register int i, j;
                   1261:        register int noff;
                   1262:        register l_fp *coffs = ees->codeoffsets;
                   1263:        l_fp offset, tmp;
                   1264:        double dispersion;      /* ++++ */
                   1265:        int lostsync, isinsync;
                   1266:        int samples = ees->nsamples;
                   1267:        int samplelog = 0;      /* keep "gcc -Wall" happy ! */
                   1268:        int samplereduce = (samples + 1) / 2;
                   1269:        double doffset;
                   1270: 
                   1271:        /* Reset things to zero so we don't have to worry later */
                   1272:        ees_reset(ees);
                   1273: 
                   1274:        if (sloppyclockflag[ees->unit]) {
                   1275:                samplelog = (samples <  2) ? 0 :
                   1276:                        (samples <  5) ? 1 :
                   1277:                        (samples <  9) ? 2 :
                   1278:                        (samples < 17) ? 3 :
                   1279:                        (samples < 33) ? 4 : 5;
                   1280:                samplereduce = (1 << samplelog);
                   1281:        }
                   1282: 
                   1283:        if (samples != last_samples &&
                   1284:            ((samples != (last_samples-1)) || samples < 3)) {
                   1285:                msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
                   1286:                        samples, last_samples, samplereduce);
                   1287:                last_samples = samples;
                   1288:        }
                   1289:        if (samples < 1) return;
                   1290: 
                   1291:        /* If requested, dump the raw data we have in the buffer */
                   1292:        if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw  data  is:");
                   1293: 
                   1294:        /* Sort the offsets, trim off the extremes, then choose one. */
                   1295:        qsort(
                   1296: #ifdef QSORT_USES_VOID_P
                   1297:            (void *)
                   1298: #else
                   1299:            (char *)
                   1300: #endif
                   1301:            coffs, (size_t)samples, sizeof(l_fp), offcompare);
                   1302: 
                   1303:        noff = samples;
                   1304:        i = 0;
                   1305:        while ((noff - i) > samplereduce) {
                   1306:                /* Trim off the sample which is further away
                   1307:                 * from the median.  We work this out by doubling
                   1308:                 * the median, subtracting off the end samples, and
                   1309:                 * looking at the sign of the answer, using the
                   1310:                 * identity (c-b)-(b-a) == 2*b-a-c
                   1311:                 */
                   1312:                tmp = coffs[(noff + i)/2];
                   1313:                L_ADD(&tmp, &tmp);
                   1314:                L_SUB(&tmp, &coffs[i]);
                   1315:                L_SUB(&tmp, &coffs[noff-1]);
                   1316:                if (L_ISNEG(&tmp)) noff--; else i++;
                   1317:        }
                   1318: 
                   1319:        /* If requested, dump the reduce data we have in the buffer */
                   1320:        if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced    to:");
                   1321: 
                   1322:        /* What we do next depends on the setting of the sloppy clock flag.
                   1323:         * If it is on, average the remainder to derive our estimate.
                   1324:         * Otherwise, just pick a representative value from the remaining stuff
                   1325:         */
                   1326:        if (sloppyclockflag[ees->unit]) {
                   1327:                offset.l_ui = offset.l_uf = 0;
                   1328:                for (j = i; j < noff; j++)
                   1329:                    L_ADD(&offset, &coffs[j]);
                   1330:                for (j = samplelog; j > 0; j--)
                   1331:                    L_RSHIFTU(&offset);
                   1332:        }
                   1333:        else offset = coffs[i+BESTSAMPLE];
                   1334: 
                   1335:        /* Compute the dispersion as the difference between the
                   1336:         * lowest and highest offsets that remain in the
                   1337:         * consideration list.
                   1338:         *
                   1339:         * It looks like MOST clocks have MOD (max error), so halve it !
                   1340:         */
                   1341:        tmp = coffs[noff-1];
                   1342:        L_SUB(&tmp, &coffs[i]);
                   1343: #define        FRACT_SEC(n) ((1 << 30) / (n/2))
                   1344:        dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
                   1345:        if (dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog(
                   1346:                (dbg & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
                   1347:                "I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d",
                   1348:                dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
                   1349:                offset.l_f / 4295, offset.l_f,
                   1350:                (dispersion * 1526) / 100,
                   1351:                (sloppyclockflag[ees->unit]) ? " by averaging" : "",
                   1352:                FRACT_SEC(10) / 4295,
                   1353:                (coffs[0].l_f) / 4295,
                   1354:                i,
                   1355:                (coffs[i].l_f) / 4295,
                   1356:                (coffs[samples/2].l_f) / 4295,
                   1357:                (coffs[i+BESTSAMPLE].l_f) / 4295,
                   1358:                noff-1,
                   1359:                (coffs[noff-1].l_f) / 4295,
                   1360:                (coffs[samples-1].l_f) / 4295);
                   1361: 
                   1362:        /* Are we playing silly wotsits ?
                   1363:         * If we are using all data, see if there is a "small" delta,
                   1364:         * and if so, blurr this with 3/4 of the delta from the last value
                   1365:         */
                   1366:        if (ees->usealldata && ees->offset.l_uf) {
                   1367:                long diff = (long) (ees->offset.l_uf - offset.l_uf);
                   1368: 
                   1369:                /* is the delta small enough ? */
                   1370:                if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
                   1371:                        int samd = (64 * 4) / samples;
                   1372:                        long new;
                   1373:                        if (samd < 2) samd = 2;
                   1374:                        new = offset.l_uf + ((diff * (samd -1)) / samd);
                   1375: 
                   1376:                        /* Sign change -> need to fix up int part */
                   1377:                        if ((new & 0x80000000) !=
                   1378:                            (((long) offset.l_uf) & 0x80000000))
                   1379:                        {       NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
                   1380:                                        msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), so add %d",
                   1381:                                                new & 0x80000000,
                   1382:                                                ((long) offset.l_uf) & 0x80000000,
                   1383:                                                new, (long) offset.l_uf,
                   1384:                                                (new < 0) ? -1 : 1);
                   1385:                                offset.l_ui += (new < 0) ? -1 : 1;
                   1386:                        }
                   1387:                        dispersion /= 4;
                   1388:                        if (dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) msyslog(
                   1389:                                (dbg & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
                   1390:                                "I: [%x] Smooth data: %ld -> %ld, dispersion now %f",
                   1391:                                dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
                   1392:                                ((long) offset.l_uf) / 4295, new / 4295,
                   1393:                                (dispersion * 1526) / 100);
                   1394:                        offset.l_uf = (unsigned long) new;
                   1395:                }
                   1396:                else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
                   1397:                        (dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
                   1398:                        "[%x] No smooth as delta not %d < %ld < %d",
                   1399:                        dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
                   1400:                        - FRACT_SEC(100), diff, FRACT_SEC(100));
                   1401:        }
                   1402:        else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
                   1403:                (dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
                   1404:                "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
                   1405:                dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
                   1406:                ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
                   1407:                offset.l_f, ees->offset.l_f - offset.l_f);
                   1408: 
                   1409:        /* Collect offset info for debugging info */
                   1410:        ees->offset = offset;
                   1411:        ees->lowoffset = coffs[i];
                   1412:        ees->highoffset = coffs[noff-1];
                   1413: 
                   1414:        /* Determine synchronization status.  Can be unsync'd either
                   1415:         * by a report from the clock or by a leap hold.
                   1416:         *
                   1417:         * Loss of the radio signal for a short time does not cause
                   1418:         * us to go unsynchronised, since the receiver keeps quite
                   1419:         * good time on its own.  The spec says 20ms in 4 hours; the
                   1420:         * observed drift in our clock (Cambridge) is about a second
                   1421:         * a day, but even that keeps us within the inherent tolerance
                   1422:         * of the clock for about 15 minutes. Observation shows that
                   1423:         * the typical "short" outage is 3 minutes, so to allow us
                   1424:         * to ride out those, we will give it 5 minutes.
                   1425:         */
                   1426:        lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
                   1427:        isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
                   1428: 
                   1429:        /* Done.  Use time of last good, synchronised code as the
                   1430:         * reference time, and lastsampletime as the receive time.
                   1431:         */
                   1432:        if (ees->fix_pending) {
                   1433:                msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
                   1434:                        ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
                   1435:                ees->fix_pending = 0;
                   1436:        }
                   1437:        LFPTOD(&offset, doffset);
                   1438:        refclock_receive(ees->peer);
                   1439:        ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
                   1440: }
                   1441: 
                   1442: /* msfees_poll - called by the transmit procedure */
                   1443: static void
                   1444: msfees_poll(
                   1445:        int unit,
                   1446:        struct peer *peer
                   1447:        )
                   1448: {
                   1449:        if (unit >= MAXUNITS) {
                   1450:                msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
                   1451:                        unit);
                   1452:                return;
                   1453:        }
                   1454:        if (!unitinuse[unit]) {
                   1455:                msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
                   1456:                        unit);
                   1457:                return;
                   1458:        }
                   1459: 
                   1460:        ees_process(eesunits[unit]);
                   1461: 
                   1462:        if ((current_time - eesunits[unit]->lasttime) > 150)
                   1463:            ees_event(eesunits[unit], CEVNT_FAULT);
                   1464: }
                   1465: 
                   1466: 
                   1467: #else
                   1468: int refclock_msfees_bs;
                   1469: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>