Annotation of embedaddon/ntp/ntpd/refclock_msfees.c, revision 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>