/contrib/ntp/clockstuff/chutest.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 816 lines · 539 code · 81 blank · 196 comment · 102 complexity · 489ad21b3b7857b601ec25c02fcf63c7 MD5 · raw file

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