diff options
Diffstat (limited to 'ntpd/refclock_jupiter.c')
| -rw-r--r-- | ntpd/refclock_jupiter.c | 745 |
1 files changed, 324 insertions, 421 deletions
diff --git a/ntpd/refclock_jupiter.c b/ntpd/refclock_jupiter.c index 8d6cde2481a7..815786a37986 100644 --- a/ntpd/refclock_jupiter.c +++ b/ntpd/refclock_jupiter.c @@ -35,6 +35,7 @@ # include <config.h> #endif +/* This clock *REQUIRES* the PPS API to be available */ #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) #include "ntpd.h" @@ -42,15 +43,15 @@ #include "ntp_refclock.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" +#include "ntp_calendar.h" +#include "ntp_calgps.h" +#include "timespecops.h" #include <stdio.h> #include <ctype.h> #include "jupiter.h" - -#ifdef HAVE_PPSAPI -# include "ppsapi_timepps.h" -#endif +#include "ppsapi_timepps.h" #ifdef WORDS_BIGENDIAN #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) @@ -108,23 +109,18 @@ */ struct instance { struct peer *peer; /* peer */ - u_int pollcnt; /* poll message counter */ - u_int polled; /* Hand in a time sample? */ -#ifdef HAVE_PPSAPI + pps_params_t pps_params; /* pps parameters */ pps_info_t pps_info; /* last pps data */ pps_handle_t pps_handle; /* pps handle */ - u_int assert; /* pps edge to use */ - u_int hardpps; /* enable kernel mode */ - struct timespec ts; /* last timestamp */ -#endif - l_fp limit; - u_int gpos_gweek; /* Current GPOS GPS week number */ - u_int gpos_sweek; /* Current GPOS GPS seconds into week */ - u_int gweek; /* current GPS week number */ - u_int32 lastsweek; /* last seconds into GPS week */ - time_t timecode; /* current ntp timecode */ - u_int32 stime; /* used to detect firmware bug */ + u_int assert; /* pps edge to use */ + u_int hardpps; /* enable kernel mode */ + l_fp rcv_pps; /* last pps timestamp */ + l_fp rcv_next; /* rcv time of next reftime */ + TGpsDatum ref_next; /* next GPS time stamp to use with PPS */ + TGpsDatum piv_next; /* pivot for week date unfolding */ + uint16_t piv_hold; /* TTL for pivot value */ + uint16_t rcvtout; /* receive timeout ticker */ int wantid; /* don't reconfig on channel id msg */ u_int moving; /* mobile platform? */ u_char sloppyclockflag; /* fudge flags */ @@ -135,28 +131,27 @@ struct instance { /* * Function prototypes */ -static void jupiter_canmsg (struct instance *, u_int); +static void jupiter_canmsg (struct instance * const, u_int); static u_short jupiter_cksum (u_short *, u_int); -static int jupiter_config (struct instance *); +static int jupiter_config (struct instance * const); static void jupiter_debug (struct peer *, const char *, const char *, ...) NTP_PRINTF(3, 4); -static const char * jupiter_parse_t (struct instance *, u_short *); -static const char * jupiter_parse_gpos (struct instance *, u_short *); -static void jupiter_platform (struct instance *, u_int); +static const char * jupiter_parse_t (struct instance * const, u_short *, l_fp); +static const char * jupiter_parse_gpos(struct instance * const, u_short *); +static void jupiter_platform(struct instance * const, u_int); static void jupiter_poll (int, struct peer *); static void jupiter_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); -#ifdef HAVE_PPSAPI -static int jupiter_ppsapi (struct instance *); -static int jupiter_pps (struct instance *); -#endif /* HAVE_PPSAPI */ -static int jupiter_recv (struct instance *); -static void jupiter_receive (struct recvbuf *rbufp); -static void jupiter_reqmsg (struct instance *, u_int, u_int); -static void jupiter_reqonemsg(struct instance *, u_int); -static char * jupiter_send (struct instance *, struct jheader *); +static int jupiter_ppsapi (struct instance * const); +static int jupiter_pps (struct instance * const); +static int jupiter_recv (struct instance * const); +static void jupiter_receive (struct recvbuf * const rbufp); +static void jupiter_reqmsg (struct instance * const, u_int, u_int); +static void jupiter_reqonemsg(struct instance * const, u_int); +static char * jupiter_send (struct instance * const, struct jheader *); static void jupiter_shutdown(int, struct peer *); static int jupiter_start (int, struct peer *); +static void jupiter_ticker (int, struct peer *); /* * Transfer vector @@ -168,7 +163,7 @@ struct refclock refclock_jupiter = { jupiter_control, /* (clock control) */ noentry, /* (clock init) */ noentry, /* (clock buginfo) */ - NOFLAGS /* not used */ + jupiter_ticker /* 1HZ ticker */ }; /* @@ -180,8 +175,8 @@ jupiter_start( struct peer *peer ) { - struct refclockproc *pp; - struct instance *instance; + struct refclockproc * const pp = peer->procptr; + struct instance * up; int fd; char gpsdev[20]; @@ -197,9 +192,8 @@ jupiter_start( } /* Allocate unit structure */ - instance = emalloc_zero(sizeof(*instance)); - instance->peer = peer; - pp = peer->procptr; + up = emalloc_zero(sizeof(*up)); + up->peer = peer; pp->io.clock_recv = jupiter_receive; pp->io.srcclock = peer; pp->io.datalen = 0; @@ -207,10 +201,10 @@ jupiter_start( if (!io_addclock(&pp->io)) { close(fd); pp->io.fd = -1; - free(instance); + free(up); return (0); } - pp->unitptr = instance; + pp->unitptr = up; /* * Initialize miscellaneous variables @@ -219,26 +213,25 @@ jupiter_start( pp->clockdesc = DESCRIPTION; memcpy((char *)&pp->refid, REFID, 4); -#ifdef HAVE_PPSAPI - instance->assert = 1; - instance->hardpps = 0; + up->assert = 1; + up->hardpps = 0; /* * Start the PPSAPI interface if it is there. Default to use * the assert edge and do not enable the kernel hardpps. */ - if (time_pps_create(fd, &instance->pps_handle) < 0) { - instance->pps_handle = 0; + if (time_pps_create(fd, &up->pps_handle) < 0) { + up->pps_handle = 0; msyslog(LOG_ERR, "refclock_jupiter: time_pps_create failed: %m"); } - else if (!jupiter_ppsapi(instance)) + else if (!jupiter_ppsapi(up)) goto clean_up; -#endif /* HAVE_PPSAPI */ - + /* Ensure the receiver is properly configured */ - if (!jupiter_config(instance)) + if (!jupiter_config(up)) goto clean_up; + jupiter_pps(up); /* get current PPS state */ return (1); clean_up: @@ -253,112 +246,158 @@ clean_up: static void jupiter_shutdown(int unit, struct peer *peer) { - struct instance *instance; - struct refclockproc *pp; - - pp = peer->procptr; - instance = pp->unitptr; - if (!instance) + struct refclockproc * const pp = peer->procptr; + struct instance * const up = pp->unitptr; + + if (!up) return; -#ifdef HAVE_PPSAPI - if (instance->pps_handle) { - time_pps_destroy(instance->pps_handle); - instance->pps_handle = 0; + if (up->pps_handle) { + time_pps_destroy(up->pps_handle); + up->pps_handle = 0; } -#endif /* HAVE_PPSAPI */ if (pp->io.fd != -1) io_closeclock(&pp->io); - free(instance); + free(up); } /* * jupiter_config - Configure the receiver */ static int -jupiter_config(struct instance *instance) +jupiter_config(struct instance * const up) { - jupiter_debug(instance->peer, __func__, "init receiver"); + jupiter_debug(up->peer, __func__, "init receiver"); /* * Initialize the unit variables */ - instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; - instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); - if (instance->moving) - jupiter_debug(instance->peer, __func__, "mobile platform"); - - instance->pollcnt = 2; - instance->polled = 0; - instance->gpos_gweek = 0; - instance->gpos_sweek = 0; - instance->gweek = 0; - instance->lastsweek = 2 * WEEKSECS; - instance->timecode = 0; - instance->stime = 0; - instance->ssize = 0; + up->sloppyclockflag = up->peer->procptr->sloppyclockflag; + up->moving = !!(up->sloppyclockflag & CLK_FLAG2); + if (up->moving) + jupiter_debug(up->peer, __func__, "mobile platform"); + + ZERO(up->rcv_next); + ZERO(up->ref_next); + ZERO(up->piv_next); + up->ssize = 0; /* Stop outputting all messages */ - jupiter_canmsg(instance, JUPITER_ALL); + jupiter_canmsg(up, JUPITER_ALL); /* Request the receiver id so we can syslog the firmware version */ - jupiter_reqonemsg(instance, JUPITER_O_ID); + jupiter_reqonemsg(up, JUPITER_O_ID); /* Flag that this the id was requested (so we don't get called again) */ - instance->wantid = 1; + up->wantid = 1; /* Request perodic time mark pulse messages */ - jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); + jupiter_reqmsg(up, JUPITER_O_PULSE, 1); /* Request perodic geodetic position status */ - jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); + jupiter_reqmsg(up, JUPITER_O_GPOS, 1); /* Set application platform type */ - if (instance->moving) - jupiter_platform(instance, JUPITER_I_PLAT_MED); + if (up->moving) + jupiter_platform(up, JUPITER_I_PLAT_MED); else - jupiter_platform(instance, JUPITER_I_PLAT_LOW); + jupiter_platform(up, JUPITER_I_PLAT_LOW); return (1); } -#ifdef HAVE_PPSAPI +static void +jupiter_checkpps( + struct refclockproc * const pp, + struct instance * const up + ) +{ + l_fp tstamp, delta; + struct calendar cd; + + if (jupiter_pps(up) || !up->piv_next.weeks) + return; + + /* check delay between pulse message and pulse. */ + delta = up->rcv_pps; /* set by jupiter_pps() */ + L_SUB(&delta, &up->rcv_next); /* recv time pulse message */ + if (delta.l_ui != 0 || delta.l_uf >= 0xC0000000) { + up->ref_next.weeks = 0; /* consider as consumed... */ + return; + } + + pp->lastrec = up->rcv_pps; + tstamp = ntpfp_from_gpsdatum(&up->ref_next); + refclock_process_offset(pp, tstamp, up->rcv_pps, pp->fudgetime1); + up->rcvtout = 2; + + gpscal_to_calendar(&cd, &up->ref_next); + refclock_save_lcode(pp, ntpcal_iso8601std(NULL, 0, &cd), + (size_t)-1); + up->ref_next.weeks = 0; /* consumed... */ +} + +/* + * jupiter_ticker - process periodic checks + */ +static void +jupiter_ticker(int unit, struct peer *peer) +{ + struct refclockproc * const pp = peer->procptr; + struct instance * const up = pp->unitptr; + + if (!up) + return; + + /* check if we can add another sample now */ + jupiter_checkpps(pp, up); + + /* check the pivot update cycle */ + if (up->piv_hold && !--up->piv_hold) + ZERO(up->piv_next); + + if (up->rcvtout) + --up->rcvtout; + else if (pp->coderecv != pp->codeproc) + refclock_samples_expire(pp, 1); +} + /* * Initialize PPSAPI */ int jupiter_ppsapi( - struct instance *instance /* unit structure pointer */ + struct instance * const up /* unit structure pointer */ ) { int capability; - if (time_pps_getcap(instance->pps_handle, &capability) < 0) { + if (time_pps_getcap(up->pps_handle, &capability) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_getcap failed: %m"); return (0); } - memset(&instance->pps_params, 0, sizeof(pps_params_t)); - if (!instance->assert) - instance->pps_params.mode = capability & PPS_CAPTURECLEAR; + memset(&up->pps_params, 0, sizeof(pps_params_t)); + if (!up->assert) + up->pps_params.mode = capability & PPS_CAPTURECLEAR; else - instance->pps_params.mode = capability & PPS_CAPTUREASSERT; - if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { + up->pps_params.mode = capability & PPS_CAPTUREASSERT; + if (!(up->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { msyslog(LOG_ERR, "refclock_jupiter: invalid capture edge %d", - instance->assert); + up->assert); return (0); } - instance->pps_params.mode |= PPS_TSFMT_TSPEC; - if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { + up->pps_params.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(up->pps_handle, &up->pps_params) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_setparams failed: %m"); return (0); } - if (instance->hardpps) { - if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, - instance->pps_params.mode & ~PPS_TSFMT_TSPEC, + if (up->hardpps) { + if (time_pps_kcbind(up->pps_handle, PPS_KC_HARDPPS, + up->pps_params.mode & ~PPS_TSFMT_TSPEC, PPS_TSFMT_TSPEC) < 0) { msyslog(LOG_ERR, "refclock_jupiter: time_pps_kcbind failed: %m"); @@ -366,15 +405,15 @@ jupiter_ppsapi( } hardpps_enable = 1; } -/* instance->peer->precision = PPS_PRECISION; */ +/* up->peer->precision = PPS_PRECISION; */ #if DEBUG if (debug) { - time_pps_getparams(instance->pps_handle, &instance->pps_params); - jupiter_debug(instance->peer, __func__, + time_pps_getparams(up->pps_handle, &up->pps_params); + jupiter_debug(up->peer, __func__, "pps capability 0x%x version %d mode 0x%x kern %d", - capability, instance->pps_params.api_version, - instance->pps_params.mode, instance->hardpps); + capability, up->pps_params.api_version, + up->pps_params.mode, up->hardpps); } #endif @@ -387,48 +426,44 @@ jupiter_ppsapi( * Return 0 on failure and 1 on success. */ static int -jupiter_pps(struct instance *instance) +jupiter_pps(struct instance * const up) { pps_info_t pps_info; struct timespec timeout, ts; - double dtemp; l_fp tstmp; /* * Convert the timespec nanoseconds field to ntp l_fp units. */ - if (instance->pps_handle == 0) + if (up->pps_handle == 0) return 1; timeout.tv_sec = 0; timeout.tv_nsec = 0; - memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); - if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, + memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); + if (time_pps_fetch(up->pps_handle, PPS_TSFMT_TSPEC, &up->pps_info, &timeout) < 0) return 1; - if (instance->pps_params.mode & PPS_CAPTUREASSERT) { + if (up->pps_params.mode & PPS_CAPTUREASSERT) { if (pps_info.assert_sequence == - instance->pps_info.assert_sequence) + up->pps_info.assert_sequence) return 1; - ts = instance->pps_info.assert_timestamp; - } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { + ts = up->pps_info.assert_timestamp; + } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { if (pps_info.clear_sequence == - instance->pps_info.clear_sequence) + up->pps_info.clear_sequence) return 1; - ts = instance->pps_info.clear_timestamp; + ts = up->pps_info.clear_timestamp; } else { return 1; } - if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) + + tstmp = tspec_stamp_to_lfp(ts); + if (L_ISEQU(&tstmp, &up->rcv_pps)) return 1; - instance->ts = ts; - tstmp.l_ui = (u_int32)ts.tv_sec + JAN_1970; - dtemp = ts.tv_nsec * FRAC / 1e9; - tstmp.l_uf = (u_int32)dtemp; - instance->peer->procptr->lastrec = tstmp; + up->rcv_pps = tstmp; return 0; } -#endif /* HAVE_PPSAPI */ /* * jupiter_poll - jupiter watchdog routine @@ -436,37 +471,25 @@ jupiter_pps(struct instance *instance) static void jupiter_poll(int unit, struct peer *peer) { - struct instance *instance; - struct refclockproc *pp; + struct refclockproc * const pp = peer->procptr; + struct instance * const up = pp->unitptr; - pp = peer->procptr; - instance = pp->unitptr; - - /* - * You don't need to poll this clock. It puts out timecodes - * once per second. If asked for a timestamp, take note. - * The next time a timecode comes in, it will be fed back. - */ + pp->polls++; /* - * If we haven't had a response in a while, reset the receiver. + * If we have new samples since last poll, everything is fine. + * if not, blarb loudly. */ - if (instance->pollcnt > 0) { - instance->pollcnt--; + if (pp->coderecv != pp->codeproc) { + refclock_receive(peer); + refclock_report(peer, CEVNT_NOMINAL); } else { refclock_report(peer, CEVNT_TIMEOUT); /* Request the receiver id to trigger a reconfig */ - jupiter_reqonemsg(instance, JUPITER_O_ID); - instance->wantid = 0; + jupiter_reqonemsg(up, JUPITER_O_ID); + up->wantid = 0; } - - /* - * polled every 64 seconds. Ask jupiter_receive to hand in - * a timestamp. - */ - instance->polled = 1; - pp->polls++; } /* @@ -480,30 +503,21 @@ jupiter_control( struct peer *peer /* peer structure pointer */ ) { - struct refclockproc *pp; - struct instance *instance; + struct refclockproc * const pp = peer->procptr; + struct instance * const up = pp->unitptr; + u_char sloppyclockflag; - pp = peer->procptr; - instance = pp->unitptr; - - DTOLFP(pp->fudgetime2, &instance->limit); - /* Force positive value. */ - if (L_ISNEG(&instance->limit)) - L_NEG(&instance->limit); + up->assert = !(pp->sloppyclockflag & CLK_FLAG3); + jupiter_ppsapi(up); -#ifdef HAVE_PPSAPI - instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); - jupiter_ppsapi(instance); -#endif /* HAVE_PPSAPI */ - - sloppyclockflag = instance->sloppyclockflag; - instance->sloppyclockflag = pp->sloppyclockflag; - if ((instance->sloppyclockflag & CLK_FLAG2) != + sloppyclockflag = up->sloppyclockflag; + up->sloppyclockflag = pp->sloppyclockflag; + if ((up->sloppyclockflag & CLK_FLAG2) != (sloppyclockflag & CLK_FLAG2)) { jupiter_debug(peer, __func__, "mode switch: reset receiver"); - jupiter_config(instance); + jupiter_config(up); return; } } @@ -513,49 +527,43 @@ jupiter_control( * Gag me! */ static void -jupiter_receive(struct recvbuf *rbufp) +jupiter_receive(struct recvbuf * const rbufp) { + struct peer * const peer = rbufp->recv_peer; + struct refclockproc * const pp = peer->procptr; + struct instance * const up = pp->unitptr; + size_t bpcnt; - int cc, size, ppsret; - time_t last_timecode; - u_int32 laststime; + int cc, size; const char *cp; u_char *bp; u_short *sp; struct jid *ip; struct jheader *hp; - struct peer *peer; - struct refclockproc *pp; - struct instance *instance; - l_fp tstamp; /* Initialize pointers and read the timecode and timestamp */ - peer = rbufp->recv_peer; - pp = peer->procptr; - instance = pp->unitptr; - bp = (u_char *)rbufp->recv_buffer; bpcnt = rbufp->recv_length; /* This shouldn't happen */ - if (bpcnt > sizeof(instance->sbuf) - instance->ssize) - bpcnt = sizeof(instance->sbuf) - instance->ssize; + if (bpcnt > sizeof(up->sbuf) - up->ssize) + bpcnt = sizeof(up->sbuf) - up->ssize; /* Append to input buffer */ - memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); - instance->ssize += bpcnt; + memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); + up->ssize += bpcnt; /* While there's at least a header and we parse an intact message */ - while (instance->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { - instance->pollcnt = 2; - - tstamp = rbufp->recv_time; - hp = (struct jheader *)instance->sbuf; + while (up->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(up)) > 0) { + hp = (struct jheader *)up->sbuf; sp = (u_short *)(hp + 1); size = cc - sizeof(*hp); switch (getshort(hp->id)) { case JUPITER_O_PULSE: + /* first see if we can push another sample: */ + jupiter_checkpps(pp, up); + if (size != sizeof(struct jpulse)) { jupiter_debug(peer, __func__, "pulse: len %d != %u", @@ -563,87 +571,24 @@ jupiter_receive(struct recvbuf *rbufp) refclock_report(peer, CEVNT_BADREPLY); break; } - - /* - * 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 + + /* Parse timecode (even when there's no pps) + * + * 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, __func__, - "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. + * after the one requested. + * + * But since we feed samples only when a new PPS + * pulse is found we can simply ignore that and + * aggregate/update any existing timing message. */ - 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) { + if ((cp = jupiter_parse_t(up, sp, rbufp->recv_time)) != NULL) { jupiter_debug(peer, __func__, "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 + (u_int32)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: @@ -655,7 +600,7 @@ jupiter_receive(struct recvbuf *rbufp) break; } - if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { + if ((cp = jupiter_parse_gpos(up, sp)) != NULL) { jupiter_debug(peer, __func__, "gpos: %s", cp); break; @@ -681,16 +626,16 @@ jupiter_receive(struct recvbuf *rbufp) 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; + if (up->wantid) + up->wantid = 0; else { jupiter_debug(peer, __func__, "reset receiver"); - jupiter_config(instance); + jupiter_config(up); /* * Restore since jupiter_config() just * zeroed it */ - instance->ssize = cc; + up->ssize = cc; } break; @@ -699,144 +644,94 @@ jupiter_receive(struct recvbuf *rbufp) getshort(hp->id)); break; } - instance->ssize -= cc; - if (instance->ssize < 0) { + up->ssize -= cc; + if (up->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); + } else if (up->ssize > 0) + memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); } } static const char * -jupiter_parse_t(struct instance *instance, u_short *sp) +jupiter_parse_t( + struct instance * const up, + u_short * sp, + l_fp rcvtime + ) { - struct tm *tm; - char *cp; struct jpulse *jp; u_int32 sweek; - time_t last_timecode; u_short flags; - + l_fp fofs; + jp = (struct jpulse *)sp; + flags = getshort(jp->flags); + /* Toss if not designated "valid" by the gps. + * !!NOTE!! do *not* kill data received so far! + */ + if ((flags & JUPITER_O_PULSE_VALID) == 0) { + refclock_report(up->peer, CEVNT_BADTIME); + return ("time mark not valid"); + } + + up->rcv_next = rcvtime; /* remember when this happened */ + /* The timecode is presented as seconds into the current GPS week */ sweek = DS2UI(jp->sweek) % WEEKSECS; - + /* check if we have to apply the UTC offset ourselves */ + if ((flags & JUPITER_O_PULSE_UTC) == 0) { + struct timespec tofs; + tofs.tv_sec = getshort(jp->offs); + tofs.tv_nsec = DS2I(jp->offns); + fofs = tspec_intv_to_lfp(tofs); + L_NEG(&fofs); + } else { + ZERO(fofs); + } + /* * 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). + * important value in the pulse message). + * + * So we pick the pivot value from the other messages like gpos + * or chan if we can. Of course, the PULSE message can be in UTC + * or GPS time scale, and the other messages are simply always + * GPS time. * - * If we already know the current GPS week, increment it when - * we wrap into a new week. + * But as long as the difference between the time stamps is less + * than a half week, the unfolding of a week time is unambigeous + * and well suited for the problem we have here. And we won't + * see *that* many leap seconds, ever. */ - 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, __func__, - "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, __func__, - "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, __func__, - "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, __func__, - "UTC <none> (gweek/sweek %u/%u)", - instance->gweek, sweek); - else { - /* XXX debugging */ - tm = gmtime(&last_timecode); - cp = asctime(tm); - - jupiter_debug(instance->peer, __func__, - "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"); + if (up->piv_next.weeks) { + up->ref_next = gpscal_from_weektime2( + sweek, fofs, &up->piv_next); + up->piv_next = up->ref_next; + } else { + up->ref_next = gpscal_from_weektime1( + sweek, fofs, rcvtime); } + - /* 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 const char * -jupiter_parse_gpos(struct instance *instance, u_short *sp) +jupiter_parse_gpos( + struct instance * const up, + u_short * sp + ) { struct jgpos *jg; - time_t t; - struct tm *tm; + struct calendar tref; char *cp; + struct timespec tofs; + uint16_t raw_week; + uint32_t raw_secs; jg = (struct jgpos *)sp; @@ -845,31 +740,22 @@ jupiter_parse_gpos(struct instance *instance, u_short *sp) * 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_sweek = DS2UI(jg->sweek); - instance->gpos_gweek = basedate_expand_gpsweek(getshort(jg->gweek)); - - /* according to the protocol spec, the seconds-in-week cannot - * exceed the nominal value: Is it really necessary to normalise - * the seconds??? - */ - 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, __func__, - "GPS %.24s (gweek/sweek %u/%u)", - cp, instance->gpos_gweek, instance->gpos_sweek); + raw_week = getshort(jg->gweek); + raw_secs = DS2UI(jg->sweek); + tofs.tv_sec = 0; + tofs.tv_nsec = DS2UI(jg->nsweek); + up->piv_next = gpscal_from_gpsweek(raw_week, raw_secs, + tspec_intv_to_lfp(tofs)); + up->piv_hold = 60; + + gpscal_to_calendar(&tref, &up->piv_next); + cp = ntpcal_iso8601std(NULL, 0, &tref); + jupiter_debug(up->peer, __func__, + "GPS %s (gweek/sweek %hu/%u)", + cp, (unsigned short)raw_week, (unsigned int)raw_secs); return (NULL); } @@ -906,7 +792,10 @@ jupiter_debug( /* Checksum and transmit a message to the Jupiter */ static char * -jupiter_send(struct instance *instance, struct jheader *hp) +jupiter_send( + struct instance * const up, + struct jheader * hp + ) { u_int len, size; ssize_t cc; @@ -923,7 +812,7 @@ jupiter_send(struct instance *instance, struct jheader *hp) size += (len + 1) * sizeof(u_short); } - if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { + if ((cc = write(up->peer->procptr->io.fd, (char *)hp, size)) < 0) { msnprintf(errstr, sizeof(errstr), "write: %m"); return (errstr); } else if (cc != (int)size) { @@ -947,8 +836,11 @@ static struct { /* An interval of zero means to output on trigger */ static void -jupiter_reqmsg(struct instance *instance, u_int id, - u_int interval) +jupiter_reqmsg( + struct instance * const up, + u_int id, + u_int interval + ) { struct jheader *hp; struct jrequest *rp; @@ -959,8 +851,8 @@ jupiter_reqmsg(struct instance *instance, u_int id, rp = &reqmsg.jrequest; rp->trigger = putshort(interval == 0); rp->interval = putshort(interval); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); + if ((cp = jupiter_send(up, hp)) != NULL) + jupiter_debug(up->peer, __func__, "%u: %s", id, cp); } /* Cancel periodic message output */ @@ -971,15 +863,18 @@ static struct jheader canmsg = { }; static void -jupiter_canmsg(struct instance *instance, u_int id) +jupiter_canmsg( + struct instance * const up, + 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, __func__, "%u: %s", id, cp); + if ((cp = jupiter_send(up, hp)) != NULL) + jupiter_debug(up->peer, __func__, "%u: %s", id, cp); } /* Request a single message output */ @@ -990,15 +885,18 @@ static struct jheader reqonemsg = { }; static void -jupiter_reqonemsg(struct instance *instance, u_int id) +jupiter_reqonemsg( + struct instance * const up, + 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, __func__, "%u: %s", id, cp); + if ((cp = jupiter_send(up, hp)) != NULL) + jupiter_debug(up->peer, __func__, "%u: %s", id, cp); } /* Set the platform dynamics */ @@ -1013,7 +911,10 @@ static struct { }; static void -jupiter_platform(struct instance *instance, u_int platform) +jupiter_platform( + struct instance * const up, + u_int platform + ) { struct jheader *hp; struct jplat *pp; @@ -1022,8 +923,8 @@ jupiter_platform(struct instance *instance, u_int platform) hp = &platmsg.jheader; pp = &platmsg.jplat; pp->platform = putshort(platform); - if ((cp = jupiter_send(instance, hp)) != NULL) - jupiter_debug(instance->peer, __func__, "%u: %s", platform, cp); + if ((cp = jupiter_send(up, hp)) != NULL) + jupiter_debug(up->peer, __func__, "%u: %s", platform, cp); } /* Checksum "len" shorts */ @@ -1042,7 +943,9 @@ jupiter_cksum(u_short *sp, u_int len) /* Return the size of the next message (or zero if we don't have it all yet) */ static int -jupiter_recv(struct instance *instance) +jupiter_recv( + struct instance * const up + ) { int n, len, size, cc; struct jheader *hp; @@ -1051,22 +954,22 @@ jupiter_recv(struct instance *instance) /* Must have at least a header's worth */ cc = sizeof(*hp); - size = instance->ssize; + size = up->ssize; if (size < cc) return (0); /* Search for the sync short if missing */ - sp = instance->sbuf; + sp = up->sbuf; hp = (struct jheader *)sp; if (getshort(hp->sync) != JUPITER_SYNC) { /* Wasn't at the front, sync up */ - jupiter_debug(instance->peer, __func__, "syncing"); + jupiter_debug(up->peer, __func__, "syncing"); bp = (u_char *)sp; n = size; while (n >= 2) { if (bp[0] != (JUPITER_SYNC & 0xff)) { /* - jupiter_debug(instance->peer, __func__, + jupiter_debug(up->peer, __func__, "{0x%x}", bp[0]); */ ++bp; @@ -1076,29 +979,29 @@ jupiter_recv(struct instance *instance) if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) break; /* - jupiter_debug(instance->peer, __func__, + jupiter_debug(up->peer, __func__, "{0x%x 0x%x}", bp[0], bp[1]); */ bp += 2; n -= 2; } /* - jupiter_debug(instance->peer, __func__, "\n"); + jupiter_debug(up->peer, __func__, "\n"); */ /* Shuffle data to front of input buffer */ if (n > 0) memcpy(sp, bp, n); size = n; - instance->ssize = size; + up->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, __func__, "bad header checksum!"); + jupiter_debug(up->peer, __func__, "bad header checksum!"); /* This is drastic but checksum errors should be rare */ - instance->ssize = 0; + up->ssize = 0; return (0); } @@ -1113,10 +1016,10 @@ jupiter_recv(struct instance *instance) /* Check payload checksum */ sp = (u_short *)(hp + 1); if (jupiter_cksum(sp, len) != getshort(sp[len])) { - jupiter_debug(instance->peer, + jupiter_debug(up->peer, __func__, "bad payload checksum!"); /* This is drastic but checksum errors should be rare */ - instance->ssize = 0; + up->ssize = 0; return (0); } cc += n; |
