📄 chutest.c
字号:
* to come out at 300 ms. Thus, peer.distance in the CHU peer structure * is set to 290 ms and we compute delays which are at least 10 ms long. * The following are 290 ms and 10 ms expressed in u_fp format */#define CHUDISTANCE 0x00004a3d#define CHUBASEDELAY 0x0000028f/* * To compute a quality for the estimate (a pseudo delay) we add a * fixed 10 ms for each missing code in the minute and add to this * the sum of the differences between the remaining offsets and the * estimated sample offset. */#define CHUDELAYPENALTY 0x0000028f/* * Other constant stuff */#define CHUPRECISION (-9) /* what the heck */#define CHUREFID "CHU\0"/* * Default fudge factors */#define DEFPROPDELAY 0x00624dd3 /* 0.0015 seconds, 1.5 ms */#define DEFFILTFUDGE 0x000d1b71 /* 0.0002 seconds, 200 us *//* * Hacks to avoid excercising the multiplier. I have no pride. */#define MULBY10(x) (((x)<<3) + ((x)<<1))#define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */#define MULBY24(x) (((x)<<4) + ((x)<<3))/* * Constants for use when multiplying by 0.1. ZEROPTONE is 0.1 * as an l_fp fraction, NZPOBITS is the number of significant bits * in ZEROPTONE. */#define ZEROPTONE 0x1999999a#define NZPOBITS 29/* * The CHU table. This gives the expected time of arrival of each * character after the on-time second and is computed as follows: * The CHU time code is sent at 300 bps. Your average UART will * synchronize at the edge of the start bit and will consider the * character complete at the center of the first stop bit, i.e. * 0.031667 ms later. Thus the expected time of each interrupt * is the start bit time plus 0.031667 seconds. These times are * in chutable[]. To this we add such things as propagation delay * and delay fudge factor. */#define CHARDELAY 0x081b4e80static u_long chutable[NCHUCHARS] = { 0x2147ae14 + CHARDELAY, /* 0.130 (exactly) */ 0x2ac08312 + CHARDELAY, /* 0.167 (exactly) */ 0x34395810 + CHARDELAY, /* 0.204 (exactly) */ 0x3db22d0e + CHARDELAY, /* 0.241 (exactly) */ 0x472b020c + CHARDELAY, /* 0.278 (exactly) */ 0x50a3d70a + CHARDELAY, /* 0.315 (exactly) */ 0x5a1cac08 + CHARDELAY, /* 0.352 (exactly) */ 0x63958106 + CHARDELAY, /* 0.389 (exactly) */ 0x6d0e5604 + CHARDELAY, /* 0.426 (exactly) */ 0x76872b02 + CHARDELAY, /* 0.463 (exactly) */};/* * Keep the fudge factors separately so they can be set even * when no clock is configured. */static l_fp propagation_delay;static l_fp fudgefactor;static l_fp offset_fudge;/* * We keep track of the start of the year, watching for changes. * We also keep track of whether the year is a leap year or not. * All because stupid CHU doesn't include the year in the time code. */static u_long yearstart;/* * Imported from the timer module */extern u_long current_time;extern struct event timerqueue[];/* * Time conversion tables imported from the library */extern u_long ustotslo[];extern u_long ustotsmid[];extern u_long ustotshi[];/* * init_chu - initialize internal chu driver data */voidinit_chu(void){ /* * Initialize fudge factors to default. */ propagation_delay.l_ui = 0; propagation_delay.l_uf = DEFPROPDELAY; fudgefactor.l_ui = 0; fudgefactor.l_uf = DEFFILTFUDGE; offset_fudge = propagation_delay; L_ADD(&offset_fudge, &fudgefactor); yearstart = 0;}voidchufilter( struct chucode *chuc, l_fp *rtime ){ register int i; register u_long date_ui; register u_long tmp; register u_char *code; int isneg; int imin; int imax; u_long reftime; l_fp off[NCHUCHARS]; l_fp ts; int day, hour, minute, second; static u_char lastcode[NCHUCHARS]; extern u_long calyearstart(); extern char *mfptoa(); void chu_process(); extern char *prettydate(); /* * We'll skip the checks made in the kernel, but assume they've * been done. This means that all characters are BCD and * the intercharacter spacing isn't unreasonable. */ /* * print the code */ for (i = 0; i < NCHUCHARS; i++) printf("%c%c", (chuc->codechars[i] & 0xf) + '0', ((chuc->codechars[i]>>4) & 0xf) + '0'); printf("\n"); /* * Format check. Make sure the two halves match. */ for (i = 0; i < NCHUCHARS/2; i++) if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) { (void) printf("Bad format, halves don't match\n"); return; } /* * Break out the code into the BCD nibbles. Only need to fiddle * with the first half since both are identical. Note the first * BCD character is the low order nibble, the second the high order. */ code = lastcode; for (i = 0; i < NCHUCHARS/2; i++) { *code++ = chuc->codechars[i] & 0xf; *code++ = (chuc->codechars[i] >> 4) & 0xf; } /* * If the first nibble isn't a 6, we're up the creek */ code = lastcode; if (*code++ != 6) { (void) printf("Bad format, no 6 at start\n"); return; } /* * Collect the day, the hour, the minute and the second. */ day = *code++; day = MULBY10(day) + *code++; day = MULBY10(day) + *code++; hour = *code++; hour = MULBY10(hour) + *code++; minute = *code++; minute = MULBY10(minute) + *code++; second = *code++; second = MULBY10(second) + *code++; /* * Sanity check the day and time. Note that this * only occurs on the 31st through the 39th second * of the minute. */ if (day < 1 || day > 366 || hour > 23 || minute > 59 || second < 31 || second > 39) { (void) printf("Failed date sanity check: %d %d %d %d\n", day, hour, minute, second); return; } /* * Compute seconds into the year. */ tmp = (u_long)(MULBY24((day-1)) + hour); /* hours */ tmp = MULBY60(tmp) + (u_long)minute; /* minutes */ tmp = MULBY60(tmp) + (u_long)second; /* seconds */ /* * Now the fun begins. We demand that the received time code * be within CLOCK_WAYTOOBIG of the receive timestamp, but * there is uncertainty about the year the timestamp is in. * Use the current year start for the first check, this should * work most of the time. */ date_ui = tmp + yearstart; if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG) && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG)) goto codeokay; /* looks good */ /* * Trouble. Next check is to see if the year rolled over and, if * so, try again with the new year's start. */ date_ui = calyearstart(rtime->l_ui); if (date_ui != yearstart) { yearstart = date_ui; date_ui += tmp; (void) printf("time %u, code %u, difference %d\n", date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui); if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG) && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG)) goto codeokay; /* okay this time */ } ts.l_uf = 0; ts.l_ui = yearstart; printf("yearstart %s\n", prettydate(&ts)); printf("received %s\n", prettydate(rtime)); ts.l_ui = date_ui; printf("date_ui %s\n", prettydate(&ts)); /* * Here we know the year start matches the current system * time. One remaining possibility is that the time code * is in the year previous to that of the system time. This * is only worth checking if the receive timestamp is less * than CLOCK_WAYTOOBIG seconds into the new year. */ if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) { date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG); if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG) goto codeokay; } /* * One last possibility is that the time stamp is in the year * following the year the system is in. Try this one before * giving up. */ date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */ if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) { printf("Date hopelessly off\n"); return; /* hopeless, let it sync to other peers */ } codeokay: reftime = date_ui; /* * We've now got the integral seconds part of the time code (we hope). * The fractional part comes from the table. We next compute * the offsets for each character. */ for (i = 0; i < NCHUCHARS; i++) { register u_long tmp2; off[i].l_ui = date_ui; off[i].l_uf = chutable[i]; tmp = chuc->codetimes[i].tv_sec + JAN_1970; TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2); M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2); } /* * Here is a *big* problem. What one would normally * do here on a machine with lots of clock bits (say * a Vax or the gizmo board) is pick the most positive * offset and the estimate, since this is the one that * is most likely suffered the smallest interrupt delay. * The trouble is that the low order clock bit on an IBM * RT, which is the machine I had in mind when doing this, * ticks at just under the millisecond mark. This isn't * precise enough. What we can do to improve this is to * average all 10 samples and rely on the second level * filtering to pick the least delayed estimate. Trouble * is, this means we have to divide a 64 bit fixed point * number by 10, a procedure which really sucks. Oh, well. * First compute the sum. */ date_ui = 0; tmp = 0; for (i = 0; i < NCHUCHARS; i++) M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf); if (M_ISNEG(date_ui, tmp)) isneg = 1; else isneg = 0; /* * Here is a multiply-by-0.1 optimization that should apply * just about everywhere. If the magnitude of the sum * is less than 9 we don't have to worry about overflow * out of a 64 bit product, even after rounding. */ if (date_ui < 9 || date_ui > 0xfffffff7) { register u_long prod_ui; register u_long prod_uf; prod_ui = prod_uf = 0; /* * This code knows the low order bit in 0.1 is zero */ for (i = 1; i < NZPOBITS; i++) { M_LSHIFT(date_ui, tmp); if (ZEROPTONE & (1<<i)) M_ADD(prod_ui, prod_uf, date_ui, tmp); } /* * Done, round it correctly. Prod_ui contains the * fraction. */ if (prod_uf & 0x80000000) prod_ui++; if (isneg) date_ui = 0xffffffff; else date_ui = 0; tmp = prod_ui; /* * date_ui is integral part, tmp is fraction. */ } else { register u_long prod_ovr; register u_long prod_ui; register u_long prod_uf; register u_long highbits; prod_ovr = prod_ui = prod_uf = 0; if (isneg) highbits = 0xffffffff; /* sign extend */ else highbits = 0; /* * This code knows the low order bit in 0.1 is zero */ for (i = 1; i < NZPOBITS; i++) { M_LSHIFT3(highbits, date_ui, tmp); if (ZEROPTONE & (1<<i)) M_ADD3(prod_ovr, prod_uf, prod_ui, highbits, date_ui, tmp); } if (prod_uf & 0x80000000) M_ADDUF(prod_ovr, prod_ui, (u_long)1); date_ui = prod_ovr; tmp = prod_ui; } /* * At this point we have the mean offset, with the integral * part in date_ui and the fractional part in tmp. Store * it in the structure. */ /* * Add in fudge factor. */ M_ADD(date_ui, tmp, offset_fudge.l_ui, offset_fudge.l_uf); /* * Find the minimun and maximum offset */ imin = imax = 0; for (i = 1; i < NCHUCHARS; i++) { if (L_ISGEQ(&off[i], &off[imax])) { imax = i; } else if (L_ISGEQ(&off[imin], &off[i])) { imin = i; } } L_ADD(&off[imin], &offset_fudge); if (imin != imax) L_ADD(&off[imax], &offset_fudge); (void) printf("mean %s, min %s, max %s\n", mfptoa(date_ui, tmp, 8), lfptoa(&off[imin], 8), lfptoa(&off[imax], 8));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -