File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / clockstuff / chutest.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp
    2:  * chutest - test the CHU clock
    3:  */
    4: 
    5: #include <stdio.h>
    6: #include <sys/types.h>
    7: #include <sys/socket.h>
    8: #include <netinet/in.h>
    9: #include <sys/ioctl.h>
   10: #include <sys/time.h>
   11: #include <sys/file.h>
   12: #include <sgtty.h>
   13: 
   14: #include "../include/ntp_fp.h"
   15: #include "../include/ntp.h"
   16: #include "../include/ntp_unixtime.h"
   17: 
   18: #ifdef CHULDISC
   19: #ifdef STREAM
   20: # ifdef HAVE_SYS_CHUDEFS_H
   21: #include <sys/chudefs.h>
   22: #endif
   23: #include <stropts.h>
   24: #endif
   25: #endif
   26: 
   27: #ifdef CHULDISC
   28: # ifdef HAVE_SYS_CHUDEFS_H
   29: #include <sys/chudefs.h>
   30: #endif
   31: #endif
   32: 
   33: #ifndef CHULDISC
   34: #ifndef STREAM
   35: #define	NCHUCHARS	(10)
   36: 
   37: struct chucode {
   38: 	u_char codechars[NCHUCHARS];	/* code characters */
   39: 	u_char ncodechars;		/* number of code characters */
   40: 	u_char chustatus;		/* not used currently */
   41: 	struct timeval codetimes[NCHUCHARS];	/* arrival times */
   42: };
   43: #endif
   44: #endif
   45: 
   46: #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
   47: 
   48: char *progname;
   49: int debug;
   50: 
   51: int dofilter = 0;	/* set to 1 when we should run filter algorithm */
   52: int showtimes = 0;	/* set to 1 when we should show char arrival times */
   53: int doprocess = 0;	/* set to 1 when we do processing analogous to driver */
   54: #ifdef CHULDISC
   55: int usechuldisc = 0;	/* set to 1 when CHU line discipline should be used */
   56: #endif
   57: #ifdef STREAM
   58: int usechuldisc = 0;	/* set to 1 when CHU line discipline should be used */
   59: #endif
   60: 
   61: struct timeval lasttv;
   62: struct chucode chudata;
   63: 
   64: extern u_long ustotslo[];
   65: extern u_long ustotsmid[];
   66: extern u_long ustotshi[];
   67: 
   68: /*
   69:  * main - parse arguments and handle options
   70:  */
   71: int
   72: main(
   73: 	int argc,
   74: 	char *argv[]
   75: 	)
   76: {
   77: 	int c;
   78: 	int errflg = 0;
   79: 	extern int ntp_optind;
   80: 	extern char *ntp_optarg;
   81: 	void init_chu();
   82: 
   83: 	progname = argv[0];
   84: 	while ((c = ntp_getopt(argc, argv, "cdfpt")) != EOF)
   85: 	    switch (c) {
   86: 		case 'c':
   87: #ifdef STREAM
   88: 		    usechuldisc = 1;
   89: 		    break;
   90: #endif
   91: #ifdef CHULDISC
   92: 		    usechuldisc = 1;
   93: 		    break;
   94: #endif
   95: #ifndef STREAM
   96: #ifndef CHULDISC
   97: 		    (void) fprintf(stderr,
   98: 				   "%s: CHU line discipline not available on this machine\n",
   99: 				   progname);
  100: 		    exit(2);
  101: #endif
  102: #endif
  103: 		case 'd':
  104: 		    ++debug;
  105: 		    break;
  106: 		case 'f':
  107: 		    dofilter = 1;
  108: 		    break;
  109: 		case 'p':
  110: 		    doprocess = 1;
  111: 		case 't':
  112: 		    showtimes = 1;
  113: 		    break;
  114: 		default:
  115: 		    errflg++;
  116: 		    break;
  117: 	    }
  118: 	if (errflg || ntp_optind+1 != argc) {
  119: #ifdef STREAM
  120: 		(void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
  121: 			       progname);
  122: #endif
  123: #ifdef CHULDISC
  124: 		(void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
  125: 			       progname);
  126: #endif
  127: #ifndef STREAM
  128: #ifndef CHULDISC
  129: 		(void) fprintf(stderr, "usage: %s [-cdft] tty_device\n",
  130: 			       progname);
  131: #endif
  132: #endif
  133: 		exit(2);
  134: 	}
  135: 
  136: 	(void) gettimeofday(&lasttv, (struct timezone *)0);
  137: 	c = openterm(argv[ntp_optind]);
  138: 	init_chu();
  139: #ifdef STREAM
  140: 	if (usechuldisc)
  141: 	    process_ldisc(c);
  142: 	else
  143: #endif
  144: #ifdef CHULDISC
  145: 	    if (usechuldisc)
  146: 		process_ldisc(c);
  147: 	    else
  148: #endif
  149: 		process_raw(c);
  150: 	/*NOTREACHED*/
  151: }
  152: 
  153: 
  154: /*
  155:  * openterm - open a port to the CHU clock
  156:  */
  157: int
  158: openterm(
  159: 	char *dev
  160: 	)
  161: {
  162: 	int s;
  163: 	struct sgttyb ttyb;
  164: 
  165: 	if (debug)
  166: 	    (void) fprintf(stderr, "Doing open...");
  167: 	if ((s = open(dev, O_RDONLY, 0777)) < 0)
  168: 	    error("open(%s)", dev, "");
  169: 	if (debug)
  170: 	    (void) fprintf(stderr, "open okay\n");
  171: 
  172: 	if (debug)
  173: 	    (void) fprintf(stderr, "Setting exclusive use...");
  174: 	if (ioctl(s, TIOCEXCL, (char *)0) < 0)
  175: 	    error("ioctl(TIOCEXCL)", "", "");
  176: 	if (debug)
  177: 	    (void) fprintf(stderr, "done\n");
  178: 	
  179: 	ttyb.sg_ispeed = ttyb.sg_ospeed = B300;
  180: 	ttyb.sg_erase = ttyb.sg_kill = 0;
  181: 	ttyb.sg_flags = EVENP|ODDP|RAW;
  182: 	if (debug)
  183: 	    (void) fprintf(stderr, "Setting baud rate et al...");
  184: 	if (ioctl(s, TIOCSETP, (char *)&ttyb) < 0)
  185: 	    error("ioctl(TIOCSETP, raw)", "", "");
  186: 	if (debug)
  187: 	    (void) fprintf(stderr, "done\n");
  188: 
  189: #ifdef CHULDISC
  190: 	if (usechuldisc) {
  191: 		int ldisc;
  192: 
  193: 		if (debug)
  194: 		    (void) fprintf(stderr, "Switching to CHU ldisc...");
  195: 		ldisc = CHULDISC;
  196: 		if (ioctl(s, TIOCSETD, (char *)&ldisc) < 0)
  197: 		    error("ioctl(TIOCSETD, CHULDISC)", "", "");
  198: 		if (debug)
  199: 		    (void) fprintf(stderr, "okay\n");
  200: 	}
  201: #endif
  202: #ifdef STREAM
  203: 	if (usechuldisc) {
  204: 
  205: 		if (debug)
  206: 		    (void) fprintf(stderr, "Poping off streams...");
  207: 		while (ioctl(s, I_POP, 0) >=0) ;
  208: 		if (debug)
  209: 		    (void) fprintf(stderr, "okay\n");
  210: 		if (debug)
  211: 		    (void) fprintf(stderr, "Pushing CHU stream...");
  212: 		if (ioctl(s, I_PUSH, "chu") < 0)
  213: 		    error("ioctl(I_PUSH, \"chu\")", "", "");
  214: 		if (debug)
  215: 		    (void) fprintf(stderr, "okay\n");
  216: 	}
  217: #endif
  218: 	return s;
  219: }
  220: 
  221: 
  222: /*
  223:  * process_raw - process characters in raw mode
  224:  */
  225: int
  226: process_raw(
  227: 	int s
  228: 	)
  229: {
  230: 	u_char c;
  231: 	int n;
  232: 	struct timeval tv;
  233: 	struct timeval difftv;
  234: 
  235: 	while ((n = read(s, &c, sizeof(char))) > 0) {
  236: 		(void) gettimeofday(&tv, (struct timezone *)0);
  237: 		if (dofilter)
  238: 		    raw_filter((unsigned int)c, &tv);
  239: 		else {
  240: 			difftv.tv_sec = tv.tv_sec - lasttv.tv_sec;
  241: 			difftv.tv_usec = tv.tv_usec - lasttv.tv_usec;
  242: 			if (difftv.tv_usec < 0) {
  243: 				difftv.tv_sec--;
  244: 				difftv.tv_usec += 1000000;
  245: 			}
  246: 			(void) printf("%02x\t%lu.%06lu\t%lu.%06lu\n",
  247: 				      c, tv.tv_sec, tv.tv_usec, difftv.tv_sec,
  248: 				      difftv.tv_usec);
  249: 			lasttv = tv;
  250: 		}
  251: 	}
  252: 
  253: 	if (n == 0) {
  254: 		(void) fprintf(stderr, "%s: zero returned on read\n", progname);
  255: 		exit(1);
  256: 	} else
  257: 	    error("read()", "", "");
  258: }
  259: 
  260: 
  261: /*
  262:  * raw_filter - run the line discipline filter over raw data
  263:  */
  264: int
  265: raw_filter(
  266: 	unsigned int c,
  267: 	struct timeval *tv
  268: 	)
  269: {
  270: 	static struct timeval diffs[10] = { 0 };
  271: 	struct timeval diff;
  272: 	l_fp ts;
  273: 	void chufilter();
  274: 
  275: 	if ((c & 0xf) > 9 || ((c>>4)&0xf) > 9) {
  276: 		if (debug)
  277: 		    (void) fprintf(stderr,
  278: 				   "character %02x failed BCD test\n");
  279: 		chudata.ncodechars = 0;
  280: 		return;
  281: 	}
  282: 
  283: 	if (chudata.ncodechars > 0) {
  284: 		diff.tv_sec = tv->tv_sec
  285: 			- chudata.codetimes[chudata.ncodechars].tv_sec;
  286: 		diff.tv_usec = tv->tv_usec
  287: 			- chudata.codetimes[chudata.ncodechars].tv_usec;
  288: 		if (diff.tv_usec < 0) {
  289: 			diff.tv_sec--;
  290: 			diff.tv_usec += 1000000;
  291: 		} /*
  292: 		    if (diff.tv_sec != 0 || diff.tv_usec > 900000) {
  293: 		    if (debug)
  294: 		    (void) fprintf(stderr,
  295: 		    "character %02x failed time test\n");
  296: 		    chudata.ncodechars = 0;
  297: 		    return;
  298: 		    } */
  299: 	}
  300: 
  301: 	chudata.codechars[chudata.ncodechars] = c;
  302: 	chudata.codetimes[chudata.ncodechars] = *tv;
  303: 	if (chudata.ncodechars > 0)
  304: 	    diffs[chudata.ncodechars] = diff;
  305: 	if (++chudata.ncodechars == 10) {
  306: 		if (doprocess) {
  307: 			TVTOTS(&chudata.codetimes[NCHUCHARS-1], &ts);
  308: 			ts.l_ui += JAN_1970;
  309: 			chufilter(&chudata, &chudata.codetimes[NCHUCHARS-1]);
  310: 		} else {
  311: 			register int i;
  312: 
  313: 			for (i = 0; i < chudata.ncodechars; i++) {
  314: 				(void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
  315: 					      chudata.codechars[i] & 0xf,
  316: 					      (chudata.codechars[i] >>4 ) & 0xf,
  317: 					      chudata.codetimes[i].tv_sec,
  318: 					      chudata.codetimes[i].tv_usec,
  319: 					      diffs[i].tv_sec, diffs[i].tv_usec);
  320: 			}
  321: 		}
  322: 		chudata.ncodechars = 0;
  323: 	}
  324: }
  325: 
  326: 
  327: /* #ifdef CHULDISC*/
  328: /*
  329:  * process_ldisc - process line discipline
  330:  */
  331: int
  332: process_ldisc(
  333: 	int s
  334: 	)
  335: {
  336: 	struct chucode chu;
  337: 	int n;
  338: 	register int i;
  339: 	struct timeval diff;
  340: 	l_fp ts;
  341: 	void chufilter();
  342: 
  343: 	while ((n = read(s, (char *)&chu, sizeof chu)) > 0) {
  344: 		if (n != sizeof chu) {
  345: 			(void) fprintf(stderr, "Expected %d, got %d\n",
  346: 				       sizeof chu, n);
  347: 			continue;
  348: 		}
  349: 
  350: 		if (doprocess) {
  351: 			TVTOTS(&chu.codetimes[NCHUCHARS-1], &ts);
  352: 			ts.l_ui += JAN_1970;
  353: 			chufilter(&chu, &ts);
  354: 		} else {
  355: 			for (i = 0; i < NCHUCHARS; i++) {
  356: 				if (i == 0)
  357: 				    diff.tv_sec = diff.tv_usec = 0;
  358: 				else {
  359: 					diff.tv_sec = chu.codetimes[i].tv_sec
  360: 						- chu.codetimes[i-1].tv_sec;
  361: 					diff.tv_usec = chu.codetimes[i].tv_usec
  362: 						- chu.codetimes[i-1].tv_usec;
  363: 					if (diff.tv_usec < 0) {
  364: 						diff.tv_sec--;
  365: 						diff.tv_usec += 1000000;
  366: 					}
  367: 				}
  368: 				(void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
  369: 					      chu.codechars[i] & 0xf, (chu.codechars[i]>>4)&0xf,
  370: 					      chu.codetimes[i].tv_sec, chu.codetimes[i].tv_usec,
  371: 					      diff.tv_sec, diff.tv_usec);
  372: 			}
  373: 		}
  374: 	}
  375: 	if (n == 0) {
  376: 		(void) fprintf(stderr, "%s: zero returned on read\n", progname);
  377: 		exit(1);
  378: 	} else
  379: 	    error("read()", "", "");
  380: }
  381: /*#endif*/
  382: 
  383: 
  384: /*
  385:  * error - print an error message
  386:  */
  387: void
  388: error(
  389: 	char *fmt,
  390: 	char *s1,
  391: 	char *s2
  392: 	)
  393: {
  394: 	(void) fprintf(stderr, "%s: ", progname);
  395: 	(void) fprintf(stderr, fmt, s1, s2);
  396: 	(void) fprintf(stderr, ": ");
  397: 	perror("");
  398: 	exit(1);
  399: }
  400: 
  401: /*
  402:  * Definitions
  403:  */
  404: #define	MAXUNITS	4	/* maximum number of CHU units permitted */
  405: #define	CHUDEV	"/dev/chu%d"	/* device we open.  %d is unit number */
  406: #define	NCHUCODES	9	/* expect 9 CHU codes per minute */
  407: 
  408: /*
  409:  * When CHU is operating optimally we want the primary clock distance
  410:  * to come out at 300 ms.  Thus, peer.distance in the CHU peer structure
  411:  * is set to 290 ms and we compute delays which are at least 10 ms long.
  412:  * The following are 290 ms and 10 ms expressed in u_fp format
  413:  */
  414: #define	CHUDISTANCE	0x00004a3d
  415: #define	CHUBASEDELAY	0x0000028f
  416: 
  417: /*
  418:  * To compute a quality for the estimate (a pseudo delay) we add a
  419:  * fixed 10 ms for each missing code in the minute and add to this
  420:  * the sum of the differences between the remaining offsets and the
  421:  * estimated sample offset.
  422:  */
  423: #define	CHUDELAYPENALTY	0x0000028f
  424: 
  425: /*
  426:  * Other constant stuff
  427:  */
  428: #define	CHUPRECISION	(-9)		/* what the heck */
  429: #define	CHUREFID	"CHU\0"
  430: 
  431: /*
  432:  * Default fudge factors
  433:  */
  434: #define	DEFPROPDELAY	0x00624dd3	/* 0.0015 seconds, 1.5 ms */
  435: #define	DEFFILTFUDGE	0x000d1b71	/* 0.0002 seconds, 200 us */
  436: 
  437: /*
  438:  * Hacks to avoid excercising the multiplier.  I have no pride.
  439:  */
  440: #define	MULBY10(x)	(((x)<<3) + ((x)<<1))
  441: #define	MULBY60(x)	(((x)<<6) - ((x)<<2))	/* watch overflow */
  442: #define	MULBY24(x)	(((x)<<4) + ((x)<<3))
  443: 
  444: /*
  445:  * Constants for use when multiplying by 0.1.  ZEROPTONE is 0.1
  446:  * as an l_fp fraction, NZPOBITS is the number of significant bits
  447:  * in ZEROPTONE.
  448:  */
  449: #define	ZEROPTONE	0x1999999a
  450: #define	NZPOBITS	29
  451: 
  452: /*
  453:  * The CHU table.  This gives the expected time of arrival of each
  454:  * character after the on-time second and is computed as follows:
  455:  * The CHU time code is sent at 300 bps.  Your average UART will
  456:  * synchronize at the edge of the start bit and will consider the
  457:  * character complete at the center of the first stop bit, i.e.
  458:  * 0.031667 ms later.  Thus the expected time of each interrupt
  459:  * is the start bit time plus 0.031667 seconds.  These times are
  460:  * in chutable[].  To this we add such things as propagation delay
  461:  * and delay fudge factor.
  462:  */
  463: #define	CHARDELAY	0x081b4e80
  464: 
  465: static u_long chutable[NCHUCHARS] = {
  466: 	0x2147ae14 + CHARDELAY,		/* 0.130 (exactly) */
  467: 	0x2ac08312 + CHARDELAY,		/* 0.167 (exactly) */
  468: 	0x34395810 + CHARDELAY,		/* 0.204 (exactly) */
  469: 	0x3db22d0e + CHARDELAY,		/* 0.241 (exactly) */
  470: 	0x472b020c + CHARDELAY,		/* 0.278 (exactly) */
  471: 	0x50a3d70a + CHARDELAY,		/* 0.315 (exactly) */
  472: 	0x5a1cac08 + CHARDELAY,		/* 0.352 (exactly) */
  473: 	0x63958106 + CHARDELAY,		/* 0.389 (exactly) */
  474: 	0x6d0e5604 + CHARDELAY,		/* 0.426 (exactly) */
  475: 	0x76872b02 + CHARDELAY,		/* 0.463 (exactly) */
  476: };
  477: 
  478: /*
  479:  * Keep the fudge factors separately so they can be set even
  480:  * when no clock is configured.
  481:  */
  482: static l_fp propagation_delay;
  483: static l_fp fudgefactor;
  484: static l_fp offset_fudge;
  485: 
  486: /*
  487:  * We keep track of the start of the year, watching for changes.
  488:  * We also keep track of whether the year is a leap year or not.
  489:  * All because stupid CHU doesn't include the year in the time code.
  490:  */
  491: static u_long yearstart;
  492: 
  493: /*
  494:  * Imported from the timer module
  495:  */
  496: extern u_long current_time;
  497: extern struct event timerqueue[];
  498: 
  499: /*
  500:  * Time conversion tables imported from the library
  501:  */
  502: extern u_long ustotslo[];
  503: extern u_long ustotsmid[];
  504: extern u_long ustotshi[];
  505: 
  506: 
  507: /*
  508:  * init_chu - initialize internal chu driver data
  509:  */
  510: void
  511: init_chu(void)
  512: {
  513: 
  514: 	/*
  515: 	 * Initialize fudge factors to default.
  516: 	 */
  517: 	propagation_delay.l_ui = 0;
  518: 	propagation_delay.l_uf = DEFPROPDELAY;
  519: 	fudgefactor.l_ui = 0;
  520: 	fudgefactor.l_uf = DEFFILTFUDGE;
  521: 	offset_fudge = propagation_delay;
  522: 	L_ADD(&offset_fudge, &fudgefactor);
  523: 
  524: 	yearstart = 0;
  525: }
  526: 
  527: 
  528: void
  529: chufilter(
  530: 	struct chucode *chuc,
  531: 	l_fp *rtime
  532: 	)
  533: {
  534: 	register int i;
  535: 	register u_long date_ui;
  536: 	register u_long tmp;
  537: 	register u_char *code;
  538: 	int isneg;
  539: 	int imin;
  540: 	int imax;
  541: 	u_long reftime;
  542: 	l_fp off[NCHUCHARS];
  543: 	l_fp ts;
  544: 	int day, hour, minute, second;
  545: 	static u_char lastcode[NCHUCHARS];
  546: 	extern u_long calyearstart();
  547: 	extern char *mfptoa();
  548: 	void chu_process();
  549: 	extern char *prettydate();
  550: 
  551: 	/*
  552: 	 * We'll skip the checks made in the kernel, but assume they've
  553: 	 * been done.  This means that all characters are BCD and
  554: 	 * the intercharacter spacing isn't unreasonable.
  555: 	 */
  556: 
  557: 	/*
  558: 	 * print the code
  559: 	 */
  560: 	for (i = 0; i < NCHUCHARS; i++)
  561: 	    printf("%c%c", (chuc->codechars[i] & 0xf) + '0',
  562: 		   ((chuc->codechars[i]>>4) & 0xf) + '0');
  563: 	printf("\n");
  564: 
  565: 	/*
  566: 	 * Format check.  Make sure the two halves match.
  567: 	 */
  568: 	for (i = 0; i < NCHUCHARS/2; i++)
  569: 	    if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
  570: 		    (void) printf("Bad format, halves don't match\n");
  571: 		    return;
  572: 	    }
  573: 	
  574: 	/*
  575: 	 * Break out the code into the BCD nibbles.  Only need to fiddle
  576: 	 * with the first half since both are identical.  Note the first
  577: 	 * BCD character is the low order nibble, the second the high order.
  578: 	 */
  579: 	code = lastcode;
  580: 	for (i = 0; i < NCHUCHARS/2; i++) {
  581: 		*code++ = chuc->codechars[i] & 0xf;
  582: 		*code++ = (chuc->codechars[i] >> 4) & 0xf;
  583: 	}
  584: 
  585: 	/*
  586: 	 * If the first nibble isn't a 6, we're up the creek
  587: 	 */
  588: 	code = lastcode;
  589: 	if (*code++ != 6) {
  590: 		(void) printf("Bad format, no 6 at start\n");
  591: 		return;
  592: 	}
  593: 
  594: 	/*
  595: 	 * Collect the day, the hour, the minute and the second.
  596: 	 */
  597: 	day = *code++;
  598: 	day = MULBY10(day) + *code++;
  599: 	day = MULBY10(day) + *code++;
  600: 	hour = *code++;
  601: 	hour = MULBY10(hour) + *code++;
  602: 	minute = *code++;
  603: 	minute = MULBY10(minute) + *code++;
  604: 	second = *code++;
  605: 	second = MULBY10(second) + *code++;
  606: 
  607: 	/*
  608: 	 * Sanity check the day and time.  Note that this
  609: 	 * only occurs on the 31st through the 39th second
  610: 	 * of the minute.
  611: 	 */
  612: 	if (day < 1 || day > 366
  613: 	    || hour > 23 || minute > 59
  614: 	    || second < 31 || second > 39) {
  615: 		(void) printf("Failed date sanity check: %d %d %d %d\n",
  616: 			      day, hour, minute, second);
  617: 		return;
  618: 	}
  619: 
  620: 	/*
  621: 	 * Compute seconds into the year.
  622: 	 */
  623: 	tmp = (u_long)(MULBY24((day-1)) + hour);	/* hours */
  624: 	tmp = MULBY60(tmp) + (u_long)minute;		/* minutes */
  625: 	tmp = MULBY60(tmp) + (u_long)second;		/* seconds */
  626: 
  627: 	/*
  628: 	 * Now the fun begins.  We demand that the received time code
  629: 	 * be within CLOCK_WAYTOOBIG of the receive timestamp, but
  630: 	 * there is uncertainty about the year the timestamp is in.
  631: 	 * Use the current year start for the first check, this should
  632: 	 * work most of the time.
  633: 	 */
  634: 	date_ui = tmp + yearstart;
  635: 	if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
  636: 	    && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
  637: 	    goto codeokay;	/* looks good */
  638: 
  639: 	/*
  640: 	 * Trouble.  Next check is to see if the year rolled over and, if
  641: 	 * so, try again with the new year's start.
  642: 	 */
  643: 	date_ui = calyearstart(rtime->l_ui);
  644: 	if (date_ui != yearstart) {
  645: 		yearstart = date_ui;
  646: 		date_ui += tmp;
  647: 		(void) printf("time %u, code %u, difference %d\n",
  648: 			      date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui);
  649: 		if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
  650: 		    && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
  651: 		    goto codeokay;	/* okay this time */
  652: 	}
  653: 
  654: 	ts.l_uf = 0;
  655: 	ts.l_ui = yearstart;
  656: 	printf("yearstart %s\n", prettydate(&ts));
  657: 	printf("received %s\n", prettydate(rtime));
  658: 	ts.l_ui = date_ui;
  659: 	printf("date_ui %s\n", prettydate(&ts));
  660: 
  661: 	/*
  662: 	 * Here we know the year start matches the current system
  663: 	 * time.  One remaining possibility is that the time code
  664: 	 * is in the year previous to that of the system time.  This
  665: 	 * is only worth checking if the receive timestamp is less
  666: 	 * than CLOCK_WAYTOOBIG seconds into the new year.
  667: 	 */
  668: 	if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) {
  669: 		date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG);
  670: 		if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG)
  671: 		    goto codeokay;
  672: 	}
  673: 
  674: 	/*
  675: 	 * One last possibility is that the time stamp is in the year
  676: 	 * following the year the system is in.  Try this one before
  677: 	 * giving up.
  678: 	 */
  679: 	date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */
  680: 	if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) {
  681: 		printf("Date hopelessly off\n");
  682: 		return;		/* hopeless, let it sync to other peers */
  683: 	}
  684: 
  685:     codeokay:
  686: 	reftime = date_ui;
  687: 	/*
  688: 	 * We've now got the integral seconds part of the time code (we hope).
  689: 	 * The fractional part comes from the table.  We next compute
  690: 	 * the offsets for each character.
  691: 	 */
  692: 	for (i = 0; i < NCHUCHARS; i++) {
  693: 		register u_long tmp2;
  694: 
  695: 		off[i].l_ui = date_ui;
  696: 		off[i].l_uf = chutable[i];
  697: 		tmp = chuc->codetimes[i].tv_sec + JAN_1970;
  698: 		TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2);
  699: 		M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
  700: 	}
  701: 
  702: 	/*
  703: 	 * Here is a *big* problem.  What one would normally
  704: 	 * do here on a machine with lots of clock bits (say
  705: 	 * a Vax or the gizmo board) is pick the most positive
  706: 	 * offset and the estimate, since this is the one that
  707: 	 * is most likely suffered the smallest interrupt delay.
  708: 	 * The trouble is that the low order clock bit on an IBM
  709: 	 * RT, which is the machine I had in mind when doing this,
  710: 	 * ticks at just under the millisecond mark.  This isn't
  711: 	 * precise enough.  What we can do to improve this is to
  712: 	 * average all 10 samples and rely on the second level
  713: 	 * filtering to pick the least delayed estimate.  Trouble
  714: 	 * is, this means we have to divide a 64 bit fixed point
  715: 	 * number by 10, a procedure which really sucks.  Oh, well.
  716: 	 * First compute the sum.
  717: 	 */
  718: 	date_ui = 0;
  719: 	tmp = 0;
  720: 	for (i = 0; i < NCHUCHARS; i++)
  721: 	    M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf);
  722: 	if (M_ISNEG(date_ui, tmp))
  723: 	    isneg = 1;
  724: 	else
  725: 	    isneg = 0;
  726: 	
  727: 	/*
  728: 	 * Here is a multiply-by-0.1 optimization that should apply
  729: 	 * just about everywhere.  If the magnitude of the sum
  730: 	 * is less than 9 we don't have to worry about overflow
  731: 	 * out of a 64 bit product, even after rounding.
  732: 	 */
  733: 	if (date_ui < 9 || date_ui > 0xfffffff7) {
  734: 		register u_long prod_ui;
  735: 		register u_long prod_uf;
  736: 
  737: 		prod_ui = prod_uf = 0;
  738: 		/*
  739: 		 * This code knows the low order bit in 0.1 is zero
  740: 		 */
  741: 		for (i = 1; i < NZPOBITS; i++) {
  742: 			M_LSHIFT(date_ui, tmp);
  743: 			if (ZEROPTONE & (1<<i))
  744: 			    M_ADD(prod_ui, prod_uf, date_ui, tmp);
  745: 		}
  746: 
  747: 		/*
  748: 		 * Done, round it correctly.  Prod_ui contains the
  749: 		 * fraction.
  750: 		 */
  751: 		if (prod_uf & 0x80000000)
  752: 		    prod_ui++;
  753: 		if (isneg)
  754: 		    date_ui = 0xffffffff;
  755: 		else
  756: 		    date_ui = 0;
  757: 		tmp = prod_ui;
  758: 		/*
  759: 		 * date_ui is integral part, tmp is fraction.
  760: 		 */
  761: 	} else {
  762: 		register u_long prod_ovr;
  763: 		register u_long prod_ui;
  764: 		register u_long prod_uf;
  765: 		register u_long highbits;
  766: 
  767: 		prod_ovr = prod_ui = prod_uf = 0;
  768: 		if (isneg)
  769: 		    highbits = 0xffffffff;	/* sign extend */
  770: 		else
  771: 		    highbits = 0;
  772: 		/*
  773: 		 * This code knows the low order bit in 0.1 is zero
  774: 		 */
  775: 		for (i = 1; i < NZPOBITS; i++) {
  776: 			M_LSHIFT3(highbits, date_ui, tmp);
  777: 			if (ZEROPTONE & (1<<i))
  778: 			    M_ADD3(prod_ovr, prod_uf, prod_ui,
  779: 				   highbits, date_ui, tmp);
  780: 		}
  781: 
  782: 		if (prod_uf & 0x80000000)
  783: 		    M_ADDUF(prod_ovr, prod_ui, (u_long)1);
  784: 		date_ui = prod_ovr;
  785: 		tmp = prod_ui;
  786: 	}
  787: 
  788: 	/*
  789: 	 * At this point we have the mean offset, with the integral
  790: 	 * part in date_ui and the fractional part in tmp.  Store
  791: 	 * it in the structure.
  792: 	 */
  793: 	/*
  794: 	 * Add in fudge factor.
  795: 	 */
  796: 	M_ADD(date_ui, tmp, offset_fudge.l_ui, offset_fudge.l_uf);
  797: 
  798: 	/*
  799: 	 * Find the minimun and maximum offset
  800: 	 */
  801: 	imin = imax = 0;
  802: 	for (i = 1; i < NCHUCHARS; i++) {
  803: 		if (L_ISGEQ(&off[i], &off[imax])) {
  804: 			imax = i;
  805: 		} else if (L_ISGEQ(&off[imin], &off[i])) {
  806: 			imin = i;
  807: 		}
  808: 	}
  809: 
  810: 	L_ADD(&off[imin], &offset_fudge);
  811: 	if (imin != imax)
  812: 	    L_ADD(&off[imax], &offset_fudge);
  813: 	(void) printf("mean %s, min %s, max %s\n",
  814: 		      mfptoa(date_ui, tmp, 8), lfptoa(&off[imin], 8),
  815: 		      lfptoa(&off[imax], 8));
  816: }

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