📄 173
字号:
X * and so the code must be prepared to handle changing flags.X */X up->sloppyclockflag = pp->sloppyclockflag;X if (pp->sloppyclockflag & CLK_FLAG2) {X up->moving = 1; /* Receiver on mobile platform */X msyslog(LOG_DEBUG, "jupiter_config: mobile platform");X } else {X up->moving = 0; /* Static Installation */X }XX /* XXX fludge flags don't make the trip from the config to here... */X#ifdef notdefX /* Configure for trailing edge triggers */X#ifdef CIOSETTETX i = ((pp->sloppyclockflag & CLK_FLAG3) != 0);X jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n",X pp->sloppyclockflag);X if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0)X msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i);X#elseX if (pp->sloppyclockflag & CLK_FLAG3)X msyslog(LOG_DEBUG, "jupiter_configure: \XNo kernel support for trailing edge trigger");X#endifX#endifXX up->pollcnt = 2;X up->polled = 0;X up->known = 0;X up->gweek = 0;X up->lastsweek = 2 * WEEKSECS;X up->timecode = 0;X up->stime = 0;X up->ssize = 0;X up->coderecv = 0;X up->nkeep = NKEEP;X if (up->nkeep > NSAMPLES)X up->nkeep = NSAMPLES;X if (up->nkeep >= 1)X up->rshift = 0;X if (up->nkeep >= 2)X up->rshift = 1;X if (up->nkeep >= 4)X up->rshift = 2;X if (up->nkeep >= 8)X up->rshift = 3;X if (up->nkeep >= 16)X up->rshift = 4;X if (up->nkeep >= 32)X up->rshift = 5;X if (up->nkeep >= 64)X up->rshift = 6;X up->nkeep = 1;X i = up->rshift;X while (i > 0) {X up->nkeep *= 2;X i--;X }XX /* Stop outputting all messages */X jupiter_canmsg(peer, JUPITER_ALL);XX /* Request the receiver id so we can syslog the firmware version */X jupiter_reqonemsg(peer, JUPITER_O_ID);XX /* Flag that this the id was requested (so we don't get called again) */X up->wantid = 1;XX /* Request perodic time mark pulse messages */X jupiter_reqmsg(peer, JUPITER_O_PULSE, 1);XX /* Set application platform type */X if (up->moving)X jupiter_platform(peer, JUPITER_I_PLAT_MED);X elseX jupiter_platform(peer, JUPITER_I_PLAT_LOW);X}XX/*X * jupiter_poll - jupiter watchdog routineX */Xstatic voidXjupiter_poll(register int unit, register struct peer *peer)X{X register struct jupiterunit *up;X register struct refclockproc *pp;XX pp = peer->procptr;X up = (struct jupiterunit *)pp->unitptr;XX /*X * You don't need to poll this clock. It puts out timecodesX * once per second. If asked for a timestamp, take note.X * The next time a timecode comes in, it will be fed back.X */XX /*X * If we haven't had a response in a while, reset the receiver.X */X if (up->pollcnt > 0) {X up->pollcnt--;X } else {X refclock_report(peer, CEVNT_TIMEOUT);XX /* Request the receiver id to trigger a reconfig */X jupiter_reqonemsg(peer, JUPITER_O_ID);X up->wantid = 0;X }XX /*X * polled every 64 seconds. Ask jupiter_receive to hand inX * a timestamp.X */X up->polled = 1;X pp->polls++;X}XX/*X * jupiter_receive - receive gps dataX * Gag me!X */Xstatic voidXjupiter_receive(register struct recvbuf *rbufp)X{X register int bpcnt, cc, size, ppsret;X register u_int32 last_timecode, laststime;X register char *cp;X register u_char *bp;X register u_short *sp;X register u_long sloppyclockflag;X register struct jupiterunit *up;X register struct jid *ip;X register struct jheader *hp;X register struct refclockproc *pp;X register struct peer *peer;XX /* Initialize pointers and read the timecode and timestamp */X peer = (struct peer *)rbufp->recv_srcclock;X pp = peer->procptr;X up = (struct jupiterunit *)pp->unitptr;XX /*X * If operating mode has been changed, then reinitialize the receiverX * before doing anything else.X */X/* XXX Sloppy clock flags are broken!! */X sloppyclockflag = up->sloppyclockflag;X up->sloppyclockflag = pp->sloppyclockflag;X if ((pp->sloppyclockflag & CLK_FLAG2) !=X (sloppyclockflag & CLK_FLAG2)) {X jupiter_debug(peer,X "jupiter_receive: mode switch: reset receiver\n");X jupiter_config(peer);X return;X }XX up->pollcnt = 2;XX bp = (u_char *)rbufp->recv_buffer;X bpcnt = rbufp->recv_length;XX /* This shouldn't happen */X if (bpcnt > sizeof(up->sbuf) - up->ssize)X bpcnt = sizeof(up->sbuf) - up->ssize;XX /* Append to input buffer */X memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt);X up->ssize += bpcnt;XX /* While there's at least a header and we parse a intact message */X while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) {X hp = (struct jheader *)up->sbuf;X sp = (u_short *)(hp + 1);X size = cc - sizeof(*hp);X switch (getshort(hp->id)) {XX case JUPITER_O_PULSE:X if (size != sizeof(struct jpulse)) {X jupiter_debug(peer,X "jupiter_receive: pulse: len %d != %u\n",X size, (int)sizeof(struct jpulse));X refclock_report(peer, CEVNT_BADREPLY);X break;X }XX /*X * There appears to be a firmware bug relatedX * to the pulse message; in addition to the oneX * per second messages, we get an extra pulseX * message once an hour (on the anniversary ofX * the cold start). It seems to come 200 msX * after the one requested. So if we've seen aX * pulse message in the last 210 ms, we skipX * this one.X */X laststime = up->stime;X up->stime = DS2UI(((struct jpulse *)sp)->stime);X if (laststime != 0 && up->stime - laststime <= 21) {X jupiter_debug(peer, "jupiter_receive: \Xavoided firmware bug (stime %.2f, laststime %.2f)\n",X (double)up->stime * 0.01, (double)laststime * 0.01);X break;X }XX /* Retrieve pps timestamp */X ppsret = jupiter_pps(peer);XX /* Parse timecode (even when there's no pps) */X last_timecode = up->timecode;X if ((cp = jupiter_parse_t(peer, sp)) != NULL) {X jupiter_debug(peer,X "jupiter_receive: pulse: %s\n", cp);X break;X }XX /* Bail if we didn't get a pps timestamp */X if (ppsret)X break;XX /* Bail if we don't have the last timecode yet */X if (last_timecode == 0)X break;XX /* Add the new sample to a median filter */X if ((cp = jupiter_offset(peer)) != NULL) {X jupiter_debug(peer,X "jupiter_receive: offset: %s\n", cp);X refclock_report(peer, CEVNT_BADTIME);X break;X }XX /*X * The clock will blurt a timecode every secondX * but we only want one when polled. If weX * havn't been polled, bail out.X */X if (!up->polled)X break;XX /*X * It's a live one! Remember this time.X */X pp->lasttime = current_time;XX /*X * Determine the reference clock offset andX * dispersion. NKEEP of NSAMPLE offsets areX * passed through a median filter.X * Save the (filtered) offset and dispersion inX * pp->offset and pp->dispersion.X */X if ((cp = jupiter_process(peer)) != NULL) {X jupiter_debug(peer,X "jupiter_receive: process: %s\n", cp);X refclock_report(peer, CEVNT_BADTIME);X break;X }X /*X * Return offset and dispersion to controlX * module. We use lastrec as both the referenceX * time and receive time in order to avoidX * being cute, like setting the reference timeX * later than the receive time, which may causeX * a paranoid protocol module to chuck out theX * data.X */X jupiter_debug(peer,X "jupiter_receive: process time: \X%4d-%03d %02d:%02d:%02d at %s, %s\n",X pp->year, pp->day,X pp->hour, pp->minute, pp->second,X prettydate(&pp->lastrec), lfptoa(&pp->offset, 6));XX refclock_receive(peer, &pp->offset, 0, pp->dispersion,X &pp->lastrec, &pp->lastrec, pp->leap);XX /*X * We have succeeded in answering the poll.X * Turn off the flag and returnX */X up->polled = 0;X break;XX case JUPITER_O_ID:X if (size != sizeof(struct jid)) {X jupiter_debug(peer,X "jupiter_receive: id: len %d != %u\n",X size, (int)sizeof(struct jid));X refclock_report(peer, CEVNT_BADREPLY);X break;X }X /*X * If we got this message because the JupiterX * just powered up, it needs to be reconfigured.X */X ip = (struct jid *)sp;X jupiter_debug(peer,X "jupiter_receive: >> %s chan ver %s, %s (%s)\n",X ip->chans, ip->vers, ip->date, ip->opts);X msyslog(LOG_DEBUG,X "jupiter_receive: %s chan ver %s, %s (%s)\n",X ip->chans, ip->vers, ip->date, ip->opts);X if (up->wantid)X up->wantid = 0;X else {X jupiter_debug(peer,X "jupiter_receive: reset receiver\n");X jupiter_config(peer);X /* Rese since jupiter_config() just zeroed it */X up->ssize = cc;X }X break;XX default:X jupiter_debug(peer,X "jupiter_receive: >> unknown message id %d\n",X getshort(hp->id));X break;X }X up->ssize -= cc;X if (up->ssize < 0) {X fprintf(stderr, "jupiter_recv: negative ssize!\n");X abort();X } else if (up->ssize > 0)X memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize);X }X record_clock_stats(&peer->srcadr, "<timecode is binary>");X}XX/*X * jupiter_offset - Calculate the offset, and add to the rolling filter.X */Xstatic char *Xjupiter_offset(register struct peer *peer)X{X register struct jupiterunit *up;X register struct refclockproc *pp;X register int i;X l_fp offset;XX pp = peer->procptr;X up = (struct jupiterunit *)pp->unitptr;XX /*X * Calculate the offsetX */X if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,X pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) {X return ("jupiter_process: clocktime failed");X }X if (pp->usec) {X TVUTOTSF(pp->usec, offset.l_uf);X } else {X MSUTOTSF(pp->msec, offset.l_uf);X }X L_ADD(&offset, &pp->fudgetime1);X up->lastref = offset; /* save last reference time */X L_SUB(&offset, &pp->lastrec); /* form true offset */XX /*X * A rolling filter. Initialize first time around.X */X i = ((up->coderecv)) % NSAMPLES;XX up->filter[i] = offset;X if (up->coderecv == 0)X for (i = 1; (u_int) i < NSAMPLES; i++)X up->filter[i] = up->filter[0];X up->coderecv++;XX return (NULL);X}XX/*X * jupiter_process - process the sample from the clock,X * passing it through a median filter and optionally averagingX * the samples. Returns offset and dispersion in "up" structure.X */Xstatic char *Xjupiter_process(register struct peer *peer)X{X register struct jupiterunit *up;X register struct refclockproc *pp;X register int i, n;X register int j, k;X l_fp offset, median, lftmp;X u_fp disp;X l_fp off[NSAMPLES];XX pp = peer->procptr;X up = (struct jupiterunit *)pp->unitptr;XX /*X * Copy the raw offsets and sort into ascending orderX */X for (i = 0; i < NSAMPLES; i++)X off[i] = up->filter[i];X qsort((char *)off, NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp);XX /*X * Reject the furthest from the median of NSAMPLES samples untilX * NKEEP samples remain.X */X i = 0;X n = NSAMPLES;X while ((n - i) > up->nkeep) {X lftmp = off[n - 1];X median = off[(n + i) / 2];X L_SUB(&lftmp, &median);X L_SUB(&median, &off[i]);X if (L_ISHIS(&median, &lftmp)) {X /* reject low end */X i++;X } else {X /* reject high end */X n--;X }X }XX /*X * Copy key values to the billboard to measure performance.X */X pp->lastref = up->lastref;X pp->coderecv = up->coderecv;X pp->nstages = up->nkeep + 2;X pp->filter[0] = off[0]; /* smallest offset */X pp->filter[1] = off[NSAMPLES-1]; /* largest offset */X for (j = 2, k = i; k < n; j++, k++)X pp->filter[j] = off[k]; /* offsets actually examined */XX /*X * Compute the dispersion based on the difference between theX * extremes of the remaining offsets. Add to this the time sinceX * the last clock update, which represents the dispersionX * increase with time. We know that NTP_MAXSKEW is 16. If theX * sum is greater than the allowed sample dispersion, bail out.X * If the loop is unlocked, return the most recent offset;X * otherwise, return the median offset.X */X lftmp = off[n - 1];X L_SUB(&lftmp, &off[i]);X disp = LFPTOFP(&lftmp);X if (disp > REFCLOCKMAXDISPERSE)X return ("Maximum dispersion exceeded");XX /*X * Now compute the offset estimate. If fudge flag 1X * is set, average the remainder, otherwise pick theX * median.X */X if (pp->sloppyclockflag & CLK_FLAG1) {X L_CLR(&lftmp);X while (i < n) {X L_ADD(&lftmp, &off[i]);X i++;X }X i = up->rshift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -