📄 refclock_jupiter.c
字号:
} /* * There appears to be a firmware bug related * to the pulse message; in addition to the one * per second messages, we get an extra pulse * message once an hour (on the anniversary of * the cold start). It seems to come 200 ms * after the one requested. So if we've seen a * pulse message in the last 210 ms, we skip * this one. */ laststime = instance->stime; instance->stime = DS2UI(((struct jpulse *)sp)->stime); if (laststime != 0 && instance->stime - laststime <= 21) { jupiter_debug(peer, "jupiter_receive", "avoided firmware bug (stime %.2f, laststime %.2f)", (double)instance->stime * 0.01, (double)laststime * 0.01); break; } /* Retrieve pps timestamp */ ppsret = jupiter_pps(instance); /* * Add one second if msg received early * (i.e. before limit, a.k.a. fudgetime2) in * the second. */ L_SUB(&tstamp, &pp->lastrec); if (!L_ISGEQ(&tstamp, &instance->limit)) ++pp->lastrec.l_ui; /* Parse timecode (even when there's no pps) */ last_timecode = instance->timecode; if ((cp = jupiter_parse_t(instance, sp)) != NULL) { jupiter_debug(peer, "jupiter_receive", "pulse: %s", cp); break; } /* Bail if we didn't get a pps timestamp */ if (ppsret) break; /* Bail if we don't have the last timecode yet */ if (last_timecode == 0) break; /* Add the new sample to a median filter */ tstamp.l_ui = JAN_1970 + last_timecode; tstamp.l_uf = 0; refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); /* * The clock will blurt a timecode every second * but we only want one when polled. If we * havn't been polled, bail out. */ if (!instance->polled) break; instance->polled = 0; /* * It's a live one! Remember this time. */ pp->lastref = pp->lastrec; refclock_receive(peer); /* * If we get here - what we got from the clock is * OK, so say so */ refclock_report(peer, CEVNT_NOMINAL); /* * We have succeeded in answering the poll. * Turn off the flag and return */ instance->polled = 0; break; case JUPITER_O_GPOS: if (size != sizeof(struct jgpos)) { jupiter_debug(peer, "jupiter_receive", "gpos: len %d != %u", size, (int)sizeof(struct jgpos)); refclock_report(peer, CEVNT_BADREPLY); break; } if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { jupiter_debug(peer, "jupiter_receive", "gpos: %s", cp); break; } break; case JUPITER_O_ID: if (size != sizeof(struct jid)) { jupiter_debug(peer, "jupiter_receive", "id: len %d != %u", size, (int)sizeof(struct jid)); refclock_report(peer, CEVNT_BADREPLY); break; } /* * If we got this message because the Jupiter * just powered instance, it needs to be reconfigured. */ ip = (struct jid *)sp; jupiter_debug(peer, "jupiter_receive", "%s chan ver %s, %s (%s)", ip->chans, ip->vers, ip->date, ip->opts); msyslog(LOG_DEBUG, "jupiter_receive: %s chan ver %s, %s (%s)", ip->chans, ip->vers, ip->date, ip->opts); if (instance->wantid) instance->wantid = 0; else { jupiter_debug(peer, "jupiter_receive", "reset receiver"); jupiter_config(instance); /* * Restore since jupiter_config() just * zeroed it */ instance->ssize = cc; } break; default: jupiter_debug(peer, "jupiter_receive", "unknown message id %d", getshort(hp->id)); break; } instance->ssize -= cc; if (instance->ssize < 0) { fprintf(stderr, "jupiter_recv: negative ssize!\n"); abort(); } else if (instance->ssize > 0) memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); }}static char *jupiter_parse_t(struct instance *instance, u_short *sp){ struct tm *tm; char *cp; struct jpulse *jp; u_int32 sweek; time_t last_timecode; u_short flags; jp = (struct jpulse *)sp; /* The timecode is presented as seconds into the current GPS week */ sweek = DS2UI(jp->sweek) % WEEKSECS; /* * If we don't know the current GPS week, calculate it from the * current time. (It's too bad they didn't include this * important value in the pulse message). We'd like to pick it * up from one of the other messages like gpos or chan but they * don't appear to be synchronous with time keeping and changes * too soon (something like 10 seconds before the new GPS * week). * * If we already know the current GPS week, increment it when * we wrap into a new week. */ if (instance->gweek == 0) { if (!instance->gpos_gweek) { return ("jupiter_parse_t: Unknown gweek"); } instance->gweek = instance->gpos_gweek; /* * Fix warps. GPOS has GPS time and PULSE has UTC. * Plus, GPOS need not be completely in synch with * the PPS signal. */ if (instance->gpos_sweek >= sweek) { if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) ++instance->gweek; } else { if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) --instance->gweek; } } else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { ++instance->gweek; jupiter_debug(instance->peer, "jupiter_parse_t", "NEW gps week %u", instance->gweek); } /* * See if the sweek stayed the same (this happens when there is * no pps pulse). * * Otherwise, look for time warps: * * - we have stored at least one lastsweek and * - the sweek didn't increase by one and * - we didn't wrap to a new GPS week * * Then we warped. */ if (instance->lastsweek == sweek) jupiter_debug(instance->peer, "jupiter_parse_t", "gps sweek not incrementing (%d)", sweek); else if (instance->lastsweek != 2 * WEEKSECS && instance->lastsweek + 1 != sweek && !(sweek == 0 && instance->lastsweek == WEEKSECS - 1)) jupiter_debug(instance->peer, "jupiter_parse_t", "gps sweek jumped (was %d, now %d)", instance->lastsweek, sweek); instance->lastsweek = sweek; /* This timecode describes next pulse */ last_timecode = instance->timecode; instance->timecode = GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; if (last_timecode == 0) /* XXX debugging */ jupiter_debug(instance->peer, "jupiter_parse_t", "UTC <none> (gweek/sweek %u/%u)", instance->gweek, sweek); else { /* XXX debugging */ tm = gmtime(&last_timecode); cp = asctime(tm); jupiter_debug(instance->peer, "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)", cp, instance->gweek, sweek); /* Billboard last_timecode (which is now the current time) */ instance->peer->procptr->year = tm->tm_year + 1900; instance->peer->procptr->day = tm->tm_yday + 1; instance->peer->procptr->hour = tm->tm_hour; instance->peer->procptr->minute = tm->tm_min; instance->peer->procptr->second = tm->tm_sec; } flags = getshort(jp->flags); /* Toss if not designated "valid" by the gps */ if ((flags & JUPITER_O_PULSE_VALID) == 0) { refclock_report(instance->peer, CEVNT_BADTIME); return ("time mark not valid"); } /* We better be sync'ed to UTC... */ if ((flags & JUPITER_O_PULSE_UTC) == 0) { refclock_report(instance->peer, CEVNT_BADTIME); return ("time mark not sync'ed to UTC"); } return (NULL);}static char *jupiter_parse_gpos(struct instance *instance, u_short *sp){ struct jgpos *jg; time_t t; struct tm *tm; char *cp; jg = (struct jgpos *)sp; if (jg->navval != 0) { /* * Solution not valid. Use caution and refuse * to determine GPS week from this message. */ instance->gpos_gweek = 0; instance->gpos_sweek = 0; return ("Navigation solution not valid"); } instance->gpos_gweek = jg->gweek; instance->gpos_sweek = DS2UI(jg->sweek); while(instance->gpos_sweek >= WEEKSECS) { instance->gpos_sweek -= WEEKSECS; ++instance->gpos_gweek; } instance->gweek = 0; t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; tm = gmtime(&t); cp = asctime(tm); jupiter_debug(instance->peer, "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)", cp, instance->gpos_gweek, instance->gpos_sweek); return (NULL);}/* * jupiter_debug - print debug messages */#if defined(__STDC__) || defined(SYS_WINNT)static voidjupiter_debug(struct peer *peer, char *function, char *fmt, ...)#elsestatic voidjupiter_debug(peer, function, fmt, va_alist) struct peer *peer; char *function; char *fmt;#endif /* __STDC__ */{ char buffer[200]; va_list ap;#if defined(__STDC__) || defined(SYS_WINNT) va_start(ap, fmt);#else va_start(ap);#endif /* __STDC__ */ /* * Print debug message to stdout * In the future, we may want to get get more creative... */ vsnprintf(buffer, sizeof(buffer), fmt, ap); record_clock_stats(&(peer->srcadr), buffer); if (debug) { fprintf(stdout, "%s: ", function); fprintf(stdout, buffer); fprintf(stdout, "\n"); fflush(stdout); } va_end(ap);}/* Checksum and transmit a message to the Jupiter */static char *jupiter_send(struct instance *instance, struct jheader *hp){ u_int len, size; int cc; u_short *sp; static char errstr[132]; size = sizeof(*hp); hp->hsum = putshort(jupiter_cksum((u_short *)hp, (size / sizeof(u_short)) - 1)); len = getshort(hp->len); if (len > 0) { sp = (u_short *)(hp + 1); sp[len] = putshort(jupiter_cksum(sp, len)); size += (len + 1) * sizeof(u_short); } if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { (void)sprintf(errstr, "write: %s", strerror(errno)); return (errstr); } else if (cc != size) { (void)sprintf(errstr, "short write (%d != %d)", cc, size); return (errstr); } return (NULL);}/* Request periodic message output */static struct { struct jheader jheader; struct jrequest jrequest;} reqmsg = { { putshort(JUPITER_SYNC), 0, putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 }, { 0, 0, 0, 0 }};/* An interval of zero means to output on trigger */static voidjupiter_reqmsg(struct instance *instance, u_int id, u_int interval){ struct jheader *hp; struct jrequest *rp; char *cp; hp = &reqmsg.jheader; hp->id = putshort(id); rp = &reqmsg.jrequest; rp->trigger = putshort(interval == 0); rp->interval = putshort(interval); if ((cp = jupiter_send(instance, hp)) != NULL) jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp);}/* Cancel periodic message output */static struct jheader canmsg = { putshort(JUPITER_SYNC), 0, 0, 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC, 0};static voidjupiter_canmsg(struct instance *instance, u_int id){ struct jheader *hp; char *cp; hp = &canmsg; hp->id = putshort(id); if ((cp = jupiter_send(instance, hp)) != NULL) jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp);}/* Request a single message output */static struct jheader reqonemsg = { putshort(JUPITER_SYNC), 0, 0, 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY, 0};static voidjupiter_reqonemsg(struct instance *instance, u_int id){ struct jheader *hp; char *cp; hp = &reqonemsg; hp->id = putshort(id); if ((cp = jupiter_send(instance, hp)) != NULL) jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp);}/* Set the platform dynamics */static struct { struct jheader jheader; struct jplat jplat;} platmsg = { { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 }, { 0, 0, 0 }};static voidjupiter_platform(struct instance *instance, u_int platform){ struct jheader *hp; struct jplat *pp; char *cp; hp = &platmsg.jheader; pp = &platmsg.jplat; pp->platform = putshort(platform); if ((cp = jupiter_send(instance, hp)) != NULL) jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp);}/* Checksum "len" shorts */static u_shortjupiter_cksum(u_short *sp, u_int len){ u_short sum, x; sum = 0; while (len-- > 0) { x = *sp++; sum += getshort(x); } return (~sum + 1);}/* Return the size of the next message (or zero if we don't have it all yet) */static intjupiter_recv(struct instance *instance){ int n, len, size, cc; struct jheader *hp; u_char *bp; u_short *sp; /* Must have at least a header's worth */ cc = sizeof(*hp); size = instance->ssize; if (size < cc) return (0); /* Search for the sync short if missing */ sp = instance->sbuf; hp = (struct jheader *)sp; if (getshort(hp->sync) != JUPITER_SYNC) { /* Wasn't at the front, sync up */ jupiter_debug(instance->peer, "jupiter_recv", "syncing"); bp = (u_char *)sp; n = size; while (n >= 2) { if (bp[0] != (JUPITER_SYNC & 0xff)) { /* jupiter_debug(instance->peer, "{0x%x}", bp[0]); */ ++bp; --n; continue; } if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) break; /* jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]); */ bp += 2; n -= 2; } /* jupiter_debug(instance->peer, "\n"); */ /* Shuffle data to front of input buffer */ if (n > 0) memcpy(sp, bp, n); size = n; instance->ssize = size; if (size < cc || hp->sync != JUPITER_SYNC) return (0); } if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != getshort(hp->hsum)) { jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!"); /* This is drastic but checksum errors should be rare */ instance->ssize = 0; return (0); } /* Check for a payload */ len = getshort(hp->len); if (len > 0) { n = (len + 1) * sizeof(u_short); /* Not enough data yet */ if (size < cc + n) return (0); /* Check payload checksum */ sp = (u_short *)(hp + 1); if (jupiter_cksum(sp, len) != getshort(sp[len])) { jupiter_debug(instance->peer, "jupiter_recv", "bad payload checksum!"); /* This is drastic but checksum errors should be rare */ instance->ssize = 0; return (0); } cc += n; } return (cc);}#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */int refclock_jupiter_bs;#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -