From: Juergen Perlinger Date: Sat, 13 Oct 2018 06:03:48 +0000 (+0200) Subject: [Bug 3535] libparse won't handle GPS week rollover X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1289389367d0a80768a650b376f64cf92e94b77f;p=thirdparty%2Fntp.git [Bug 3535] libparse won't handle GPS week rollover bk: 5bc18ac4JFajcugcOSU67J1N4SV1gQ --- diff --git a/ChangeLog b/ChangeLog index f381a093c..23d0f2ddb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +--- +* [Bug 3535] libparse won't handle GPS week rollover + - refactored handling of GPS era based on 'tos basedate' for + parse (TSIP) and JUPITER clocks + --- (4.2.8p12) 2018/08/14 Released by Harlan Stenn diff --git a/include/ntp_calendar.h b/include/ntp_calendar.h index 41c58797b..0b1f20d6b 100644 --- a/include/ntp_calendar.h +++ b/include/ntp_calendar.h @@ -93,6 +93,7 @@ extern systime_func_ptr ntpcal_set_timefunc(systime_func_ptr); #define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */ #define SECSPERAVGYEAR 31556952 /* mean year length over 400yrs */ +#define GPSWEEKS 1024 /* GPS week cycle */ /* * Gross hacks. I have illicit knowlege that there won't be overflows * here, the compiler often can't tell this. @@ -404,14 +405,21 @@ basedate_get_eracenter(void); extern time_t basedate_get_erabase(void); +extern uint32_t +basedate_get_gpsweek(void); + +extern uint32_t +basedate_expand_gpsweek(unsigned short weekno); /* * Additional support stuff for Ed Rheingold's calendrical calculations */ /* - * Start day of NTP time as days past the imaginary date 12/1/1 BC. - * (This is the beginning of the Christian Era, or BCE.) + * Start day of NTP time as days past 0000-12-31 in the proleptic + * Gregorian calendar. (So 0001-01-01 is day number 1; this is the Rata + * Die counting scheme used by Ed Rheingold in his book "Calendrical + * Calculations".) */ #define DAY_NTP_STARTS 693596 @@ -420,15 +428,25 @@ basedate_get_erabase(void); */ #define DAY_UNIX_STARTS 719163 +/* + * Start day of the GPS epoch. This is the Rata Die of 1980-01-06 + */ +#define DAY_GPS_STARTS 722819 + /* * Difference between UN*X and NTP epoch (25567). */ #define NTP_TO_UNIX_DAYS (DAY_UNIX_STARTS - DAY_NTP_STARTS) +/* + * Difference between GPS and NTP epoch (29224) + */ +#define NTP_TO_GPS_DAYS (DAY_GPS_STARTS - DAY_NTP_STARTS) + /* * Days in a normal 4 year leap year calendar cycle (1461). */ -#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (3 * 365 + 366) +#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS (4 * 365 + 1) /* * Days in a normal 100 year leap year calendar (36524). We lose a diff --git a/include/parse.h b/include/parse.h index 02dbb3021..e2caa52ea 100644 --- a/include/parse.h +++ b/include/parse.h @@ -108,7 +108,6 @@ extern unsigned int splclock (void); * some constants useful for GPS time conversion */ #define GPSORIGIN 2524953600UL /* NTP origin - GPS origin in seconds */ -#define GPSWRAP 990 /* assume week count less than this in the previous epoch */ #define GPSWEEKS 1024 /* number of weeks until the GPS epch rolls over */ /* diff --git a/libntp/calyearstart.c b/libntp/calyearstart.c index 9e3f58fb3..5616c8195 100644 --- a/libntp/calyearstart.c +++ b/libntp/calyearstart.c @@ -54,7 +54,7 @@ calmonthstart(u_int32 ntptime, const time_t *pivot) } /* - * calweekstart - get NTP time at midnight of the last monday on or + * calweekstart - get NTP time at midnight of the last Monday on or * before the current date. */ u_int32 diff --git a/libntp/ntp_calendar.c b/libntp/ntp_calendar.c index f8b7db4ea..79742688a 100644 --- a/libntp/ntp_calendar.c +++ b/libntp/ntp_calendar.c @@ -1832,6 +1832,7 @@ isocal_date_to_ntp( */ static int32_t s_baseday = NTP_TO_UNIX_DAYS; +static int32_t s_gpsweek = 0; int32_t basedate_eval_buildstamp(void) @@ -1901,6 +1902,7 @@ basedate_set_day( struct calendar jd; int32_t retv; + /* set NTP base date for NTP era unfolding */ if (day < NTP_TO_UNIX_DAYS) { msyslog(LOG_WARNING, "baseday_set_day: invalid day (%lu), UNIX epoch substituted", @@ -1912,6 +1914,17 @@ basedate_set_day( ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS); msyslog(LOG_INFO, "basedate set to %04hu-%02hu-%02hu", jd.year, (u_short)jd.month, (u_short)jd.monthday); + + /* set GPS base week for GPS week unfolding */ + day = ntpcal_weekday_ge(day + DAY_NTP_STARTS, CAL_SUNDAY) + - DAY_NTP_STARTS; + if (day < NTP_TO_GPS_DAYS) + day = NTP_TO_GPS_DAYS; + s_gpsweek = (day - NTP_TO_GPS_DAYS) / DAYSPERWEEK; + ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS); + msyslog(LOG_INFO, "gps base set to %04hu-%02hu-%02hu (week %d)", + jd.year, (u_short)jd.month, (u_short)jd.monthday, s_gpsweek); + return retv; } @@ -1934,4 +1947,29 @@ basedate_get_erabase(void) return retv; } +uint32_t +basedate_get_gpsweek(void) +{ + return s_gpsweek; +} + +uint32_t +basedate_expand_gpsweek( + unsigned short weekno + ) +{ + /* We do a fast modulus expansion here. Since all quantities are + * unsigned and we cannot go before the start of the GPS epoch + * anyway, and since the truncated GPS week number is 10 bit, the + * expansion becomes a simple sub/and/add sequence. + */ + #if GPSWEEKS != 1024 + # error GPSWEEKS defined wrong -- should be 1024! + #endif + + uint32_t diff; + diff = ((uint32_t)weekno - s_gpsweek) & (GPSWEEKS - 1); + return s_gpsweek + diff; +} + /* -*-EOF-*- */ diff --git a/libparse/clk_trimtsip.c b/libparse/clk_trimtsip.c index 64359efa0..8cf566065 100644 --- a/libparse/clk_trimtsip.c +++ b/libparse/clk_trimtsip.c @@ -265,9 +265,7 @@ cvt_trimtsip( clock_time->flags = PARSEB_POWERUP; return CVT_OK; } - if (week < GPSWRAP) { - week += GPSWEEKS; - } + week = basedate_expand_gpsweek(week); /* time OK */ @@ -351,14 +349,12 @@ cvt_trimtsip( int tls = t->t_gpsutc = (u_short) getshort((unsigned char *)&mb(12)); /* current leap correction (GPS-UTC) */ int tlsf = t->t_gpsutcleap = (u_short) getshort((unsigned char *)&mb(24)); /* new leap correction */ - t->t_weekleap = (u_short) getshort((unsigned char *)&mb(20)); /* week no of leap correction */ - if (t->t_weekleap < GPSWRAP) - t->t_weekleap = (u_short)(t->t_weekleap + GPSWEEKS); + t->t_weekleap = basedate_expand_gpsweek( + (u_short) getshort((unsigned char *)&mb(20))); /* week no of leap correction */ t->t_dayleap = (u_short) getshort((unsigned char *)&mb(22)); /* day in week of leap correction */ - t->t_week = (u_short) getshort((unsigned char *)&mb(18)); /* current week no */ - if (t->t_week < GPSWRAP) - t->t_week = (u_short)(t->t_weekleap + GPSWEEKS); + t->t_week = basedate_expand_gpsweek( + (u_short) getshort((unsigned char *)&mb(18))); /* current week no */ lbp = (unsigned char *)&mb(14); /* last update time */ if (fetch_ieee754(&lbp, IEEE_SINGLE, &t0t, trim_offsets) != IEEE_OK) diff --git a/libparse/gpstolfp.c b/libparse/gpstolfp.c index 8a3607514..6a99e8851 100644 --- a/libparse/gpstolfp.c +++ b/libparse/gpstolfp.c @@ -45,11 +45,6 @@ gpstolfp( l_fp * lfp ) { - if (weeks < GPSWRAP) - { - weeks += GPSWEEKS; - } - lfp->l_ui = (uint32_t)(weeks * SECSPERWEEK + days * SECSPERDAY + seconds + GPSORIGIN); /* convert to NTP time */ lfp->l_uf = 0; } diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index 89c920c1e..d7a6b197f 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -2112,6 +2112,10 @@ config_tos_clock( break; } } + + if (basedate_get_day() <= NTP_TO_UNIX_DAYS) + basedate_set_day(basedate_eval_buildstamp() - 11); + return ret; } diff --git a/ntpd/refclock_jupiter.c b/ntpd/refclock_jupiter.c index dbed27246..8d6cde248 100644 --- a/ntpd/refclock_jupiter.c +++ b/ntpd/refclock_jupiter.c @@ -158,10 +158,6 @@ static char * jupiter_send (struct instance *, struct jheader *); static void jupiter_shutdown(int, struct peer *); static int jupiter_start (int, struct peer *); -static u_int get_full_week(u_int base_week, u_int gpos_week); -static u_int get_base_week(void); - - /* * Transfer vector */ @@ -855,8 +851,7 @@ jupiter_parse_gpos(struct instance *instance, u_short *sp) } instance->gpos_sweek = DS2UI(jg->sweek); - instance->gpos_gweek = get_full_week(get_base_week(), - getshort(jg->gweek)); + 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 @@ -1129,56 +1124,6 @@ jupiter_recv(struct instance *instance) return (cc); } -static u_int -get_base_week(void) -{ - static int init_done /* = 0 */; - static u_int base_week; - - /* Get the build date, convert to days since GPS epoch and - * finally weeks since GPS epoch. Note that the build stamp is - * trusted once it is fetched -- only dates before the GPS epoch - * are not permitted. This will permit proper synchronisation - * for a time range of 1024 weeks starting with 00:00:00 of the - * last Sunday on or before the build time. - * - * If the impossible happens and fetching the build date fails, - * a 1024-week cycle starting with 2016-01-03 is assumed to - * avoid catastropic errors. This will work until 2035-08-19. - */ - if (!init_done) { - struct calendar bd; - if (ntpcal_get_build_date(&bd)) { - int32_t days = ntpcal_date_to_rd(&bd); - if (days > RDN_GPS_EPOCH) - days -= RDN_GPS_EPOCH; - else - days = 0; - base_week = days / 7; - } else { - base_week = 1878; /* 2016-01-03, Sunday */ - msyslog(LOG_ERR, - "refclock_jupiter: ntpcal_get_build_date() failed: %s", - "using 2016-01-03 as GPS base!"); - } - init_done = 1; - } - return base_week; -} - -static u_int -get_full_week( - u_int base_week, - u_int gpos_week - ) -{ - /* Periodic extension on base week. Since the period is 1024 - * weeks and we do unsigned arithmetic here, we can do wonderful - * things with masks and the well-defined overflow behaviour. - */ - return base_week + ((gpos_week - base_week) & 1023); -} - #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ int refclock_jupiter_bs; #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ diff --git a/ntpd/refclock_parse.c b/ntpd/refclock_parse.c index cfe2a8968..9f5b0d712 100644 --- a/ntpd/refclock_parse.c +++ b/ntpd/refclock_parse.c @@ -4256,8 +4256,7 @@ mk_utcinfo( struct tm *tm; int nc; - if (wnlsf < GPSWRAP) - wnlsf += GPSWEEKS; + wnlsf = basedate_expand_gpsweek(wnlsf); /* 'wnt' not used here: would need the same treatment as 'wnlsf */ t_ls = (time_t) wnlsf * SECSPERWEEK