📄 87
字号:
* later than the receive time, which may cause a paranoid * protocol module to chuck out the data. */ mx4200_debug(peer, "mx4200_receive: process time: "); mx4200_debug(peer, "%4d-%03d %02d:%02d:%02d at %s, %s\n", pp->year, pp->day, pp->hour, pp->minute, pp->second, prettydate(pp->lastrec), lfptoa(&pp->offset, 6)); refclock_receive(peer, &pp->offset, 0, pp->dispersion, &pp->lastrec, &pp->lastrec, pp->leap); /* * We have succeeded in answering the poll. * Turn off the flag and return */ up->polled = 0; return; } /* * Ignore all other sentence types */ return;}/* * mx4200_offset - Calculate the offset, and add to the rolling filter. */static char *mx4200_offset(peer) struct peer *peer;{ register struct mx4200unit *up; struct refclockproc *pp; register int i; l_fp offset; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; /* * Calculate the offset */ if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) { return ("mx4200_process: clocktime failed"); } if (pp->usec) { TVUTOTSF(pp->usec, offset.l_uf); } else { MSUTOTSF(pp->msec, offset.l_uf); } L_ADD(&offset, &pp->fudgetime1); up->lastref = offset; /* save last reference time */ L_SUB(&offset, &pp->lastrec); /* form true offset */ /* * A rolling filter. Initialize first time around. */ i = ((up->coderecv)) % NSAMPLES; up->filter[i] = offset; if (up->coderecv == 0) for (i = 1; (u_int) i < NSAMPLES; i++) up->filter[i] = up->filter[0]; up->coderecv++; return (NULL);}/* * mx4200_process - process the sample from the clock, * passing it through a median filter and optionally averaging * the samples. Returns offset and dispersion in "up" structure. */static char *mx4200_process(peer) struct peer *peer;{ register struct mx4200unit *up; struct refclockproc *pp; register int i, n; int j, k; l_fp offset, median, lftmp; u_fp disp; l_fp off[NSAMPLES]; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; /* * Copy the raw offsets and sort into ascending order */ for (i = 0; i < NSAMPLES; i++) off[i] = up->filter[i]; qsort((char *)off, NSAMPLES, sizeof(l_fp), mx4200_cmpl_fp); /* * Reject the furthest from the median of NSAMPLES samples until * NKEEP samples remain. */ i = 0; n = NSAMPLES; while ((n - i) > up->nkeep) { lftmp = off[n - 1]; median = off[(n + i) / 2]; L_SUB(&lftmp, &median); L_SUB(&median, &off[i]); if (L_ISHIS(&median, &lftmp)) { /* reject low end */ i++; } else { /* reject high end */ n--; } } /* * Copy key values to the billboard to measure performance. */ pp->lastref = up->lastref; pp->coderecv = up->coderecv; pp->nstages = up->nkeep + 2; pp->filter[0] = off[0]; /* smallest offset */ pp->filter[1] = off[NSAMPLES-1]; /* largest offset */ for (j=2, k=i; k < n; j++, k++) pp->filter[j] = off[k]; /* offsets actually examined */ /* * Compute the dispersion based on the difference between the * extremes of the remaining offsets. Add to this the time since * the last clock update, which represents the dispersion * increase with time. We know that NTP_MAXSKEW is 16. If the * sum is greater than the allowed sample dispersion, bail out. * If the loop is unlocked, return the most recent offset; * otherwise, return the median offset. */ lftmp = off[n - 1]; L_SUB(&lftmp, &off[i]); disp = LFPTOFP(&lftmp); if (disp > REFCLOCKMAXDISPERSE) { return("Maximum dispersion exceeded"); } /* * Now compute the offset estimate. If the sloppy clock * flag 1 is set, average the remainder, otherwise pick the * median. */ if (pp->sloppyclockflag && CLK_FLAG1) { L_CLR(&lftmp); while (i < n) { L_ADD(&lftmp, &off[i]); i++; } i = up->rshift; while (i > 0) { L_RSHIFT(&lftmp); i--; } offset = lftmp; } else { i = (n + i) / 2; offset = off[i]; } /* * The payload: filtered offset and dispersion. */ pp->offset = offset; pp->dispersion = disp; return(NULL);}/* Compare two l_fp's, used with qsort() */int#ifdef QSORT_USES_VOID_Pmx4200_cmpl_fp(p1, p2) const void *p1, *p2;{ register const l_fp *fp1 = (const l_fp *)p1; register const l_fp *fp2 = (const l_fp *)p2;#elsemx4200_cmpl_fp(fp1, fp2) register const l_fp *fp1; register const l_fp *fp2;{#endif /* not QSORT_USES_VOID_P */ if (!L_ISGEQ(fp1, fp2)) return (-1); if (L_ISEQU(fp1, fp2)) return (0); return (1);}/* * Parse a mx4200 time recovery message. Returns a string if error. * * A typical message looks like this. Checksum has already been stripped. * * $PMVXG,830,T,YYYY,MM,DD,HH:MM:SS,U,S,FFFFFF,PPPPP,BBBBBB,LL * * Field Field Contents * ----- -------------- * Block Label: $PMVXG * Sentence Type: 830=Time Recovery Results * This sentence is output approximately 1 second * preceding the 1PPS output. It indicates the * exact time of the next pulse, whether or not the * time mark will be valid (based on operator-specified * error tolerance), the time to which the pulse is * synchronized, the receiver operating mode, * and the time error of the *last* 1PPS output. * 1 Time Mark Valid: T=Valid, F=Not Valid * 2 Year: 1993- * 3 Month of Year: 1-12 * 4 Day of Month: 1-31 * 5 Time of Day: HH:MM:SS * 6 Time Synchronization: U=UTC, G=GPS * 7 Time Recovery Mode: D=Dynamic, S=Static, * K=Known Position, N=No Time Recovery * 8 Oscillator Offset: The filter's estimate of the oscillator * frequency error, in parts per billion (ppb). * 9 Time Mark Error: The computed error of the *last* pulse * output, in nanoseconds. * 10 User Time Bias: Operator specified bias, in nanoseconds * 11 Leap Second Flag: Indicates that a leap second will * occur. This value is usually zero, except during * the week prior to the leap second occurence, when * this value will be set to +1 or -1. A value of * +1 indicates that GPS time will be 1 second * further ahead of UTC time. * */static char *mx4200_parse_t(peer) struct peer *peer;{ struct refclockproc *pp; struct mx4200unit *up; int sentence_type, valid; int year, yearday, month, monthday, hour, minute, second, leapsec; char *cp; pp = peer->procptr; up = (struct mx4200unit *)pp->unitptr; cp = pp->lastcode; if ((cp = strchr(cp, ',')) == NULL) return ("no rec-type"); cp++; /* Sentence type */ sentence_type = strtol(cp, &cp, 10); if (sentence_type != PMVXG_D_TRECOVOUT) return ("wrong rec-type"); /* Pulse valid indicator */ if (*cp++ != ',') return ("no pulse-valid"); if (*cp == 'T') valid = 1; else if (*cp == 'F') valid = 0; else return ("bad pulse-valid"); cp++; /* Year */ if (*cp++ != ',') return ("no year"); year = strtol(cp, &cp, 10); /* Month of year */ if (*cp++ != ',') return ("no month"); month = strtol(cp, &cp, 10); /* Day of month */ if (*cp++ != ',') return ("no month day"); monthday = strtol(cp, &cp, 10); /* Hour */ if (*cp++ != ',') return ("no hour"); hour = strtol(cp, &cp, 10); /* Minute */ if (*cp++ != ':') return ("no minute"); minute = strtol(cp, &cp, 10); /* Second */ if (*cp++ != ':') return ("no second"); second = strtol(cp, &cp, 10); /* Time indicator */ if (*cp++ != ',') return ("no time indicator"); if (*cp == 'G') return ("synchronized to GPS; should be UTC"); else if (*cp != 'U') return ("not synchronized to UTC"); cp++; /* Time recovery mode */ if (*cp++ != ',' || *cp++ == '\0') return ("no time mode"); /* Oscillator offset */ if ((cp = strchr(cp, ',')) == NULL) return ("no osc off"); cp++; /* Time mark error */ /* (by request, always less than 0.5 usec (500 nsec), so ignore) */ if ((cp = strchr(cp, ',')) == NULL) return ("no time mark err"); cp++; /* User time bias */ /* (by request, always zero, so ignore */ if ((cp = strchr(cp, ',')) == NULL) return ("no user bias"); cp++; /* Leap second flag */ if ((cp = strchr(cp, ',')) == NULL) return ("no leap"); cp++; leapsec = strtol(cp, &cp, 10); /* * Check for insane time (allow for possible leap seconds) */ if (second > 60 || minute > 59 || hour > 23 || second < 0 || minute < 0 || hour < 0) { mx4200_debug(peer, "mx4200_parse_t: bad time %02d:%02d:%02d", hour, minute, second); if (leapsec != 0) mx4200_debug(peer, " (leap %+d\n)", leapsec); mx4200_debug(peer, "\n"); refclock_report(peer, CEVNT_BADTIME); return ("bad time"); } /* * Check for insane date */ if (monthday > 31 || month > 12 || monthday < 1 || month < 1 || year < 1996) { mx4200_debug(peer, "mx4200_parse_t: bad date (%4d-%02d-%02d)\n", year, month, monthday); refclock_report(peer, CEVNT_BADDATE); return; } /* * Silly Hack for MX4200: * ASCII message is for *next* 1PPS signal, but we have the * timestamp for the *last* 1PPS signal. So we have to subtract * a second. Discard if we are on a month boundary to avoid * possible leap seconds and leap days. */ second--; if (second < 0) { second = 59; minute--; if (minute < 0) { minute = 59; hour--; if (hour < 0) { hour = 23; monthday--; if (monthday < 1) { return ("sorry, month boundary"); } } } } /* * Calculate Julian date */ if (!(yearday = mx4200_jday(year, month, monthday))) { mx4200_debug(peer, "mx4200_parse_t: bad julian date %d (%4d-%02d-%02d)\n", yearday, year, month, monthday); refclock_report(peer, CEVNT_BADDATE); return("invalid julian date"); } /* * Setup leap second indicator */ if (leapsec == 0) pp->leap = LEAP_NOWARNING; else if (leapsec == 1) pp->leap = LEAP_ADDSECOND; else if (leapsec == -1) pp->leap = LEAP_DELSECOND; else pp->leap = LEAP_NOTINSYNC; /* shouldn't happen */ /* * Copy time data for billboard monitoring. */ pp->year = year; pp->day = yearday; pp->hour = hour; pp->minute = minute; pp->second = second; pp->msec = 0; pp->usec = 0; /* * Toss if sentence is marked invalid */ if (!valid || pp->leap == LEAP_NOTINSYNC) { mx4200_debug(peer, "mx4200_parse_t: time mark not valid\n"); refclock_report(peer, CEVNT_BADTIME); return ("pulse invalid"); } return (NULL);}/* * Calculate the checksum */static u_charmx4200_cksum(cp, n) register char *cp; register u_int n;{ register u_char ck; for (ck = 0; n-- > 0; cp++) ck ^= *cp; return (ck);}/* * Tables to compute the day of year. Viva la leap. */static day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};static day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};/* * Calculate the the Julian Day */static intmx4200_jday(year, month, monthday) int year; int month; int monthday;{ register int day, i; int leap_year; /* * Is this a leap year ? */ if (year % 4) { leap_year = 0; /* FALSE */ } else { if (year % 100) { leap_year = 1; /* TRUE */ } else { if (year % 400) { leap_year = 0; /* FALSE */ } else { leap_year = 1; /* TRUE */ } } } /* * Calculate the Julian Date */ day = monthday; if (leap_year) { /* a leap year */ if (day > day2tab[month - 1]) { return (0); } for (i = 0; i < month - 1; i++) day += day2tab[i]; } else { /* not a leap year */ if (day > day1tab[month - 1]) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -