1c0b746e5SOllivier Robert /* 29c2daa00SOllivier Robert * Copyright (c) 1997, 1998, 2003 3c0b746e5SOllivier Robert * The Regents of the University of California. All rights reserved. 4c0b746e5SOllivier Robert * 5c0b746e5SOllivier Robert * Redistribution and use in source and binary forms, with or without 6c0b746e5SOllivier Robert * modification, are permitted provided that the following conditions 7c0b746e5SOllivier Robert * are met: 8c0b746e5SOllivier Robert * 1. Redistributions of source code must retain the above copyright 9c0b746e5SOllivier Robert * notice, this list of conditions and the following disclaimer. 10c0b746e5SOllivier Robert * 2. Redistributions in binary form must reproduce the above copyright 11c0b746e5SOllivier Robert * notice, this list of conditions and the following disclaimer in the 12c0b746e5SOllivier Robert * documentation and/or other materials provided with the distribution. 13c0b746e5SOllivier Robert * 3. All advertising materials mentioning features or use of this software 14c0b746e5SOllivier Robert * must display the following acknowledgement: 15c0b746e5SOllivier Robert * This product includes software developed by the University of 16c0b746e5SOllivier Robert * California, Lawrence Berkeley Laboratory. 17c0b746e5SOllivier Robert * 4. The name of the University may not be used to endorse or promote 18c0b746e5SOllivier Robert * products derived from this software without specific prior 19c0b746e5SOllivier Robert * written permission. 20c0b746e5SOllivier Robert * 21c0b746e5SOllivier Robert * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22c0b746e5SOllivier Robert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c0b746e5SOllivier Robert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c0b746e5SOllivier Robert * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25c0b746e5SOllivier Robert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c0b746e5SOllivier Robert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c0b746e5SOllivier Robert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c0b746e5SOllivier Robert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c0b746e5SOllivier Robert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c0b746e5SOllivier Robert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c0b746e5SOllivier Robert * SUCH DAMAGE. 32c0b746e5SOllivier Robert */ 33c0b746e5SOllivier Robert 34c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 35c0b746e5SOllivier Robert # include <config.h> 36c0b746e5SOllivier Robert #endif 37c0b746e5SOllivier Robert 389c2daa00SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) 39c0b746e5SOllivier Robert 40c0b746e5SOllivier Robert #include "ntpd.h" 41c0b746e5SOllivier Robert #include "ntp_io.h" 42c0b746e5SOllivier Robert #include "ntp_refclock.h" 43c0b746e5SOllivier Robert #include "ntp_unixtime.h" 44c0b746e5SOllivier Robert #include "ntp_stdlib.h" 45c0b746e5SOllivier Robert 46224ba2bdSOllivier Robert #include <stdio.h> 47224ba2bdSOllivier Robert #include <ctype.h> 48224ba2bdSOllivier Robert 49c0b746e5SOllivier Robert #include "jupiter.h" 50c0b746e5SOllivier Robert 519c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 52ea906c41SOllivier Robert # include "ppsapi_timepps.h" 539c2daa00SOllivier Robert #endif 54c0b746e5SOllivier Robert 552b15cb3dSCy Schubert #ifdef WORDS_BIGENDIAN 56c0b746e5SOllivier Robert #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 57c0b746e5SOllivier Robert #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 58c0b746e5SOllivier Robert #else 592b15cb3dSCy Schubert #define getshort(s) ((u_short)(s)) 602b15cb3dSCy Schubert #define putshort(s) ((u_short)(s)) 61c0b746e5SOllivier Robert #endif 62c0b746e5SOllivier Robert 63c0b746e5SOllivier Robert /* 64c0b746e5SOllivier Robert * This driver supports the Rockwell Jupiter GPS Receiver board 65c0b746e5SOllivier Robert * adapted to precision timing applications. It requires the 66c0b746e5SOllivier Robert * ppsclock line discipline or streams module described in the 67c0b746e5SOllivier Robert * Line Disciplines and Streams Drivers page. It also requires a 68c0b746e5SOllivier Robert * gadget box and 1-PPS level converter, such as described in the 69c0b746e5SOllivier Robert * Pulse-per-second (PPS) Signal Interfacing page. 70c0b746e5SOllivier Robert * 71c0b746e5SOllivier Robert * It may work (with minor modifications) with other Rockwell GPS 72c0b746e5SOllivier Robert * receivers such as the CityTracker. 73c0b746e5SOllivier Robert */ 74c0b746e5SOllivier Robert 75c0b746e5SOllivier Robert /* 76c0b746e5SOllivier Robert * GPS Definitions 77c0b746e5SOllivier Robert */ 78c0b746e5SOllivier Robert #define DEVICE "/dev/gps%d" /* device name and unit */ 79c0b746e5SOllivier Robert #define SPEED232 B9600 /* baud */ 80c0b746e5SOllivier Robert 81c0b746e5SOllivier Robert /* 82c0b746e5SOllivier Robert * Radio interface parameters 83c0b746e5SOllivier Robert */ 84c0b746e5SOllivier Robert #define PRECISION (-18) /* precision assumed (about 4 us) */ 85c0b746e5SOllivier Robert #define REFID "GPS\0" /* reference id */ 86c0b746e5SOllivier Robert #define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ 87c0b746e5SOllivier Robert #define DEFFUDGETIME 0 /* default fudge time (ms) */ 88c0b746e5SOllivier Robert 89c0b746e5SOllivier Robert /* Unix timestamp for the GPS epoch: January 6, 1980 */ 90c0b746e5SOllivier Robert #define GPS_EPOCH 315964800 91c0b746e5SOllivier Robert 92f391d6bcSXin LI /* Rata Die Number of first day of GPS epoch. This is the number of days 93f391d6bcSXin LI * since 0000-12-31 to 1980-01-06 in the proleptic Gregorian Calendar. 94f391d6bcSXin LI */ 95f391d6bcSXin LI #define RDN_GPS_EPOCH (4*146097 + 138431 + 1) 96f391d6bcSXin LI 97c0b746e5SOllivier Robert /* Double short to unsigned int */ 98c0b746e5SOllivier Robert #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 99c0b746e5SOllivier Robert 100c0b746e5SOllivier Robert /* Double short to signed int */ 101c0b746e5SOllivier Robert #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 102c0b746e5SOllivier Robert 103c0b746e5SOllivier Robert /* One week's worth of seconds */ 104c0b746e5SOllivier Robert #define WEEKSECS (7 * 24 * 60 * 60) 105c0b746e5SOllivier Robert 106c0b746e5SOllivier Robert /* 107c0b746e5SOllivier Robert * Jupiter unit control structure. 108c0b746e5SOllivier Robert */ 1099c2daa00SOllivier Robert struct instance { 1109c2daa00SOllivier Robert struct peer *peer; /* peer */ 111c0b746e5SOllivier Robert u_int pollcnt; /* poll message counter */ 112c0b746e5SOllivier Robert u_int polled; /* Hand in a time sample? */ 1139c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 1149c2daa00SOllivier Robert pps_params_t pps_params; /* pps parameters */ 1159c2daa00SOllivier Robert pps_info_t pps_info; /* last pps data */ 1169c2daa00SOllivier Robert pps_handle_t pps_handle; /* pps handle */ 1179c2daa00SOllivier Robert u_int assert; /* pps edge to use */ 118ea906c41SOllivier Robert u_int hardpps; /* enable kernel mode */ 1199c2daa00SOllivier Robert struct timespec ts; /* last timestamp */ 1209c2daa00SOllivier Robert #endif 1219c2daa00SOllivier Robert l_fp limit; 1229c2daa00SOllivier Robert u_int gpos_gweek; /* Current GPOS GPS week number */ 1239c2daa00SOllivier Robert u_int gpos_sweek; /* Current GPOS GPS seconds into week */ 124c0b746e5SOllivier Robert u_int gweek; /* current GPS week number */ 125c0b746e5SOllivier Robert u_int32 lastsweek; /* last seconds into GPS week */ 1269c2daa00SOllivier Robert time_t timecode; /* current ntp timecode */ 127c0b746e5SOllivier Robert u_int32 stime; /* used to detect firmware bug */ 128c0b746e5SOllivier Robert int wantid; /* don't reconfig on channel id msg */ 129c0b746e5SOllivier Robert u_int moving; /* mobile platform? */ 1309c2daa00SOllivier Robert u_char sloppyclockflag; /* fudge flags */ 131c0b746e5SOllivier Robert u_short sbuf[512]; /* local input buffer */ 132c0b746e5SOllivier Robert int ssize; /* space used in sbuf */ 133c0b746e5SOllivier Robert }; 134c0b746e5SOllivier Robert 135c0b746e5SOllivier Robert /* 136c0b746e5SOllivier Robert * Function prototypes 137c0b746e5SOllivier Robert */ 1382b15cb3dSCy Schubert static void jupiter_canmsg (struct instance *, u_int); 1392b15cb3dSCy Schubert static u_short jupiter_cksum (u_short *, u_int); 1402b15cb3dSCy Schubert static int jupiter_config (struct instance *); 1412b15cb3dSCy Schubert static void jupiter_debug (struct peer *, const char *, 142*4e1ef62aSXin LI const char *, ...) NTP_PRINTF(3, 4); 1432b15cb3dSCy Schubert static const char * jupiter_parse_t (struct instance *, u_short *); 1442b15cb3dSCy Schubert static const char * jupiter_parse_gpos (struct instance *, u_short *); 1452b15cb3dSCy Schubert static void jupiter_platform (struct instance *, u_int); 1462b15cb3dSCy Schubert static void jupiter_poll (int, struct peer *); 1472b15cb3dSCy Schubert static void jupiter_control (int, const struct refclockstat *, 1482b15cb3dSCy Schubert struct refclockstat *, struct peer *); 1499c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 1502b15cb3dSCy Schubert static int jupiter_ppsapi (struct instance *); 1512b15cb3dSCy Schubert static int jupiter_pps (struct instance *); 1529c2daa00SOllivier Robert #endif /* HAVE_PPSAPI */ 1532b15cb3dSCy Schubert static int jupiter_recv (struct instance *); 1542b15cb3dSCy Schubert static void jupiter_receive (struct recvbuf *rbufp); 1552b15cb3dSCy Schubert static void jupiter_reqmsg (struct instance *, u_int, u_int); 1562b15cb3dSCy Schubert static void jupiter_reqonemsg(struct instance *, u_int); 1572b15cb3dSCy Schubert static char * jupiter_send (struct instance *, struct jheader *); 1582b15cb3dSCy Schubert static void jupiter_shutdown(int, struct peer *); 1592b15cb3dSCy Schubert static int jupiter_start (int, struct peer *); 160c0b746e5SOllivier Robert 161f391d6bcSXin LI static u_int get_full_week(u_int base_week, u_int gpos_week); 162f391d6bcSXin LI static u_int get_base_week(void); 163f391d6bcSXin LI 164f391d6bcSXin LI 165c0b746e5SOllivier Robert /* 166c0b746e5SOllivier Robert * Transfer vector 167c0b746e5SOllivier Robert */ 168c0b746e5SOllivier Robert struct refclock refclock_jupiter = { 169c0b746e5SOllivier Robert jupiter_start, /* start up driver */ 170c0b746e5SOllivier Robert jupiter_shutdown, /* shut down driver */ 171c0b746e5SOllivier Robert jupiter_poll, /* transmit poll message */ 1729c2daa00SOllivier Robert jupiter_control, /* (clock control) */ 173c0b746e5SOllivier Robert noentry, /* (clock init) */ 174c0b746e5SOllivier Robert noentry, /* (clock buginfo) */ 175c0b746e5SOllivier Robert NOFLAGS /* not used */ 176c0b746e5SOllivier Robert }; 177c0b746e5SOllivier Robert 178c0b746e5SOllivier Robert /* 179c0b746e5SOllivier Robert * jupiter_start - open the devices and initialize data for processing 180c0b746e5SOllivier Robert */ 181c0b746e5SOllivier Robert static int 182c0b746e5SOllivier Robert jupiter_start( 1839c2daa00SOllivier Robert int unit, 1849c2daa00SOllivier Robert struct peer *peer 185c0b746e5SOllivier Robert ) 186c0b746e5SOllivier Robert { 187c0b746e5SOllivier Robert struct refclockproc *pp; 1889c2daa00SOllivier Robert struct instance *instance; 1892b15cb3dSCy Schubert int fd; 190c0b746e5SOllivier Robert char gpsdev[20]; 191c0b746e5SOllivier Robert 192c0b746e5SOllivier Robert /* 193c0b746e5SOllivier Robert * Open serial port 194c0b746e5SOllivier Robert */ 1952b15cb3dSCy Schubert snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 1969c2daa00SOllivier Robert fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 1972b15cb3dSCy Schubert if (fd <= 0) { 1982b15cb3dSCy Schubert jupiter_debug(peer, "jupiter_start", "open %s: %m", 1992b15cb3dSCy Schubert gpsdev); 200c0b746e5SOllivier Robert return (0); 201c0b746e5SOllivier Robert } 202c0b746e5SOllivier Robert 203c0b746e5SOllivier Robert /* Allocate unit structure */ 2042b15cb3dSCy Schubert instance = emalloc_zero(sizeof(*instance)); 2059c2daa00SOllivier Robert instance->peer = peer; 206c0b746e5SOllivier Robert pp = peer->procptr; 207c0b746e5SOllivier Robert pp->io.clock_recv = jupiter_receive; 2082b15cb3dSCy Schubert pp->io.srcclock = peer; 209c0b746e5SOllivier Robert pp->io.datalen = 0; 210c0b746e5SOllivier Robert pp->io.fd = fd; 211c0b746e5SOllivier Robert if (!io_addclock(&pp->io)) { 2122b15cb3dSCy Schubert close(fd); 2132b15cb3dSCy Schubert pp->io.fd = -1; 2149c2daa00SOllivier Robert free(instance); 215c0b746e5SOllivier Robert return (0); 216c0b746e5SOllivier Robert } 2172b15cb3dSCy Schubert pp->unitptr = instance; 218c0b746e5SOllivier Robert 219c0b746e5SOllivier Robert /* 220c0b746e5SOllivier Robert * Initialize miscellaneous variables 221c0b746e5SOllivier Robert */ 222c0b746e5SOllivier Robert peer->precision = PRECISION; 223c0b746e5SOllivier Robert pp->clockdesc = DESCRIPTION; 224c0b746e5SOllivier Robert memcpy((char *)&pp->refid, REFID, 4); 225c0b746e5SOllivier Robert 2269c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 227ea906c41SOllivier Robert instance->assert = 1; 228ea906c41SOllivier Robert instance->hardpps = 0; 2299c2daa00SOllivier Robert /* 2309c2daa00SOllivier Robert * Start the PPSAPI interface if it is there. Default to use 2319c2daa00SOllivier Robert * the assert edge and do not enable the kernel hardpps. 2329c2daa00SOllivier Robert */ 2339c2daa00SOllivier Robert if (time_pps_create(fd, &instance->pps_handle) < 0) { 2349c2daa00SOllivier Robert instance->pps_handle = 0; 2359c2daa00SOllivier Robert msyslog(LOG_ERR, 2369c2daa00SOllivier Robert "refclock_jupiter: time_pps_create failed: %m"); 2379c2daa00SOllivier Robert } 238ea906c41SOllivier Robert else if (!jupiter_ppsapi(instance)) 2399c2daa00SOllivier Robert goto clean_up; 2409c2daa00SOllivier Robert #endif /* HAVE_PPSAPI */ 241c0b746e5SOllivier Robert 242c0b746e5SOllivier Robert /* Ensure the receiver is properly configured */ 2439c2daa00SOllivier Robert if (!jupiter_config(instance)) 2449c2daa00SOllivier Robert goto clean_up; 245c0b746e5SOllivier Robert 246c0b746e5SOllivier Robert return (1); 2479c2daa00SOllivier Robert 2489c2daa00SOllivier Robert clean_up: 2499c2daa00SOllivier Robert jupiter_shutdown(unit, peer); 2509c2daa00SOllivier Robert pp->unitptr = 0; 2519c2daa00SOllivier Robert return (0); 252c0b746e5SOllivier Robert } 253c0b746e5SOllivier Robert 254c0b746e5SOllivier Robert /* 255c0b746e5SOllivier Robert * jupiter_shutdown - shut down the clock 256c0b746e5SOllivier Robert */ 257c0b746e5SOllivier Robert static void 2589c2daa00SOllivier Robert jupiter_shutdown(int unit, struct peer *peer) 259c0b746e5SOllivier Robert { 2609c2daa00SOllivier Robert struct instance *instance; 261c0b746e5SOllivier Robert struct refclockproc *pp; 262c0b746e5SOllivier Robert 263c0b746e5SOllivier Robert pp = peer->procptr; 2642b15cb3dSCy Schubert instance = pp->unitptr; 2659c2daa00SOllivier Robert if (!instance) 2669c2daa00SOllivier Robert return; 2679c2daa00SOllivier Robert 2689c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 2699c2daa00SOllivier Robert if (instance->pps_handle) { 2709c2daa00SOllivier Robert time_pps_destroy(instance->pps_handle); 2719c2daa00SOllivier Robert instance->pps_handle = 0; 2729c2daa00SOllivier Robert } 2739c2daa00SOllivier Robert #endif /* HAVE_PPSAPI */ 2749c2daa00SOllivier Robert 2752b15cb3dSCy Schubert if (pp->io.fd != -1) 276c0b746e5SOllivier Robert io_closeclock(&pp->io); 2779c2daa00SOllivier Robert free(instance); 278c0b746e5SOllivier Robert } 279c0b746e5SOllivier Robert 280c0b746e5SOllivier Robert /* 281c0b746e5SOllivier Robert * jupiter_config - Configure the receiver 282c0b746e5SOllivier Robert */ 2839c2daa00SOllivier Robert static int 2849c2daa00SOllivier Robert jupiter_config(struct instance *instance) 285c0b746e5SOllivier Robert { 2862b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "init receiver"); 287c0b746e5SOllivier Robert 288c0b746e5SOllivier Robert /* 289c0b746e5SOllivier Robert * Initialize the unit variables 290c0b746e5SOllivier Robert */ 2919c2daa00SOllivier Robert instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; 2929c2daa00SOllivier Robert instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); 2939c2daa00SOllivier Robert if (instance->moving) 2942b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "mobile platform"); 295c0b746e5SOllivier Robert 2969c2daa00SOllivier Robert instance->pollcnt = 2; 2979c2daa00SOllivier Robert instance->polled = 0; 2989c2daa00SOllivier Robert instance->gpos_gweek = 0; 2999c2daa00SOllivier Robert instance->gpos_sweek = 0; 3009c2daa00SOllivier Robert instance->gweek = 0; 3019c2daa00SOllivier Robert instance->lastsweek = 2 * WEEKSECS; 3029c2daa00SOllivier Robert instance->timecode = 0; 3039c2daa00SOllivier Robert instance->stime = 0; 3049c2daa00SOllivier Robert instance->ssize = 0; 305c0b746e5SOllivier Robert 306c0b746e5SOllivier Robert /* Stop outputting all messages */ 3079c2daa00SOllivier Robert jupiter_canmsg(instance, JUPITER_ALL); 308c0b746e5SOllivier Robert 309c0b746e5SOllivier Robert /* Request the receiver id so we can syslog the firmware version */ 3109c2daa00SOllivier Robert jupiter_reqonemsg(instance, JUPITER_O_ID); 311c0b746e5SOllivier Robert 312c0b746e5SOllivier Robert /* Flag that this the id was requested (so we don't get called again) */ 3139c2daa00SOllivier Robert instance->wantid = 1; 314c0b746e5SOllivier Robert 315c0b746e5SOllivier Robert /* Request perodic time mark pulse messages */ 3169c2daa00SOllivier Robert jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); 3179c2daa00SOllivier Robert 3189c2daa00SOllivier Robert /* Request perodic geodetic position status */ 3199c2daa00SOllivier Robert jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); 320c0b746e5SOllivier Robert 321c0b746e5SOllivier Robert /* Set application platform type */ 3229c2daa00SOllivier Robert if (instance->moving) 3239c2daa00SOllivier Robert jupiter_platform(instance, JUPITER_I_PLAT_MED); 324c0b746e5SOllivier Robert else 3259c2daa00SOllivier Robert jupiter_platform(instance, JUPITER_I_PLAT_LOW); 3269c2daa00SOllivier Robert 3279c2daa00SOllivier Robert return (1); 328c0b746e5SOllivier Robert } 329c0b746e5SOllivier Robert 3309c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 3319c2daa00SOllivier Robert /* 3329c2daa00SOllivier Robert * Initialize PPSAPI 3339c2daa00SOllivier Robert */ 3349c2daa00SOllivier Robert int 3359c2daa00SOllivier Robert jupiter_ppsapi( 336ea906c41SOllivier Robert struct instance *instance /* unit structure pointer */ 3379c2daa00SOllivier Robert ) 3389c2daa00SOllivier Robert { 3399c2daa00SOllivier Robert int capability; 3409c2daa00SOllivier Robert 3419c2daa00SOllivier Robert if (time_pps_getcap(instance->pps_handle, &capability) < 0) { 3429c2daa00SOllivier Robert msyslog(LOG_ERR, 3439c2daa00SOllivier Robert "refclock_jupiter: time_pps_getcap failed: %m"); 3449c2daa00SOllivier Robert return (0); 3459c2daa00SOllivier Robert } 3469c2daa00SOllivier Robert memset(&instance->pps_params, 0, sizeof(pps_params_t)); 347ea906c41SOllivier Robert if (!instance->assert) 3489c2daa00SOllivier Robert instance->pps_params.mode = capability & PPS_CAPTURECLEAR; 3499c2daa00SOllivier Robert else 3509c2daa00SOllivier Robert instance->pps_params.mode = capability & PPS_CAPTUREASSERT; 3519c2daa00SOllivier Robert if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 3529c2daa00SOllivier Robert msyslog(LOG_ERR, 3539c2daa00SOllivier Robert "refclock_jupiter: invalid capture edge %d", 354ea906c41SOllivier Robert instance->assert); 3559c2daa00SOllivier Robert return (0); 3569c2daa00SOllivier Robert } 3579c2daa00SOllivier Robert instance->pps_params.mode |= PPS_TSFMT_TSPEC; 3589c2daa00SOllivier Robert if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { 3599c2daa00SOllivier Robert msyslog(LOG_ERR, 3609c2daa00SOllivier Robert "refclock_jupiter: time_pps_setparams failed: %m"); 3619c2daa00SOllivier Robert return (0); 3629c2daa00SOllivier Robert } 363ea906c41SOllivier Robert if (instance->hardpps) { 3649c2daa00SOllivier Robert if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, 365ea906c41SOllivier Robert instance->pps_params.mode & ~PPS_TSFMT_TSPEC, 3669c2daa00SOllivier Robert PPS_TSFMT_TSPEC) < 0) { 3679c2daa00SOllivier Robert msyslog(LOG_ERR, 3689c2daa00SOllivier Robert "refclock_jupiter: time_pps_kcbind failed: %m"); 3699c2daa00SOllivier Robert return (0); 3709c2daa00SOllivier Robert } 3712b15cb3dSCy Schubert hardpps_enable = 1; 3729c2daa00SOllivier Robert } 3739c2daa00SOllivier Robert /* instance->peer->precision = PPS_PRECISION; */ 3749c2daa00SOllivier Robert 3759c2daa00SOllivier Robert #if DEBUG 3769c2daa00SOllivier Robert if (debug) { 3779c2daa00SOllivier Robert time_pps_getparams(instance->pps_handle, &instance->pps_params); 3782b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 3799c2daa00SOllivier Robert "pps capability 0x%x version %d mode 0x%x kern %d", 3809c2daa00SOllivier Robert capability, instance->pps_params.api_version, 381ea906c41SOllivier Robert instance->pps_params.mode, instance->hardpps); 3829c2daa00SOllivier Robert } 3839c2daa00SOllivier Robert #endif 3849c2daa00SOllivier Robert 3859c2daa00SOllivier Robert return (1); 3869c2daa00SOllivier Robert } 3879c2daa00SOllivier Robert 3889c2daa00SOllivier Robert /* 3899c2daa00SOllivier Robert * Get PPSAPI timestamps. 3909c2daa00SOllivier Robert * 3919c2daa00SOllivier Robert * Return 0 on failure and 1 on success. 3929c2daa00SOllivier Robert */ 3939c2daa00SOllivier Robert static int 3949c2daa00SOllivier Robert jupiter_pps(struct instance *instance) 3959c2daa00SOllivier Robert { 3969c2daa00SOllivier Robert pps_info_t pps_info; 3979c2daa00SOllivier Robert struct timespec timeout, ts; 3989c2daa00SOllivier Robert double dtemp; 3999c2daa00SOllivier Robert l_fp tstmp; 4009c2daa00SOllivier Robert 4019c2daa00SOllivier Robert /* 4029c2daa00SOllivier Robert * Convert the timespec nanoseconds field to ntp l_fp units. 4039c2daa00SOllivier Robert */ 4049c2daa00SOllivier Robert if (instance->pps_handle == 0) 4059c2daa00SOllivier Robert return 1; 4069c2daa00SOllivier Robert timeout.tv_sec = 0; 4079c2daa00SOllivier Robert timeout.tv_nsec = 0; 4089c2daa00SOllivier Robert memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); 4099c2daa00SOllivier Robert if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, 4109c2daa00SOllivier Robert &timeout) < 0) 4119c2daa00SOllivier Robert return 1; 4129c2daa00SOllivier Robert if (instance->pps_params.mode & PPS_CAPTUREASSERT) { 4139c2daa00SOllivier Robert if (pps_info.assert_sequence == 4149c2daa00SOllivier Robert instance->pps_info.assert_sequence) 4159c2daa00SOllivier Robert return 1; 4169c2daa00SOllivier Robert ts = instance->pps_info.assert_timestamp; 4179c2daa00SOllivier Robert } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { 4189c2daa00SOllivier Robert if (pps_info.clear_sequence == 4199c2daa00SOllivier Robert instance->pps_info.clear_sequence) 4209c2daa00SOllivier Robert return 1; 4219c2daa00SOllivier Robert ts = instance->pps_info.clear_timestamp; 4229c2daa00SOllivier Robert } else { 4239c2daa00SOllivier Robert return 1; 4249c2daa00SOllivier Robert } 4259c2daa00SOllivier Robert if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) 4269c2daa00SOllivier Robert return 1; 4279c2daa00SOllivier Robert instance->ts = ts; 4289c2daa00SOllivier Robert 4292b15cb3dSCy Schubert tstmp.l_ui = (u_int32)ts.tv_sec + JAN_1970; 4309c2daa00SOllivier Robert dtemp = ts.tv_nsec * FRAC / 1e9; 4319c2daa00SOllivier Robert tstmp.l_uf = (u_int32)dtemp; 4329c2daa00SOllivier Robert instance->peer->procptr->lastrec = tstmp; 4339c2daa00SOllivier Robert return 0; 4349c2daa00SOllivier Robert } 4359c2daa00SOllivier Robert #endif /* HAVE_PPSAPI */ 4369c2daa00SOllivier Robert 437c0b746e5SOllivier Robert /* 438c0b746e5SOllivier Robert * jupiter_poll - jupiter watchdog routine 439c0b746e5SOllivier Robert */ 440c0b746e5SOllivier Robert static void 4419c2daa00SOllivier Robert jupiter_poll(int unit, struct peer *peer) 442c0b746e5SOllivier Robert { 4439c2daa00SOllivier Robert struct instance *instance; 4449c2daa00SOllivier Robert struct refclockproc *pp; 445c0b746e5SOllivier Robert 446c0b746e5SOllivier Robert pp = peer->procptr; 4472b15cb3dSCy Schubert instance = pp->unitptr; 448c0b746e5SOllivier Robert 449c0b746e5SOllivier Robert /* 450c0b746e5SOllivier Robert * You don't need to poll this clock. It puts out timecodes 451c0b746e5SOllivier Robert * once per second. If asked for a timestamp, take note. 452c0b746e5SOllivier Robert * The next time a timecode comes in, it will be fed back. 453c0b746e5SOllivier Robert */ 454c0b746e5SOllivier Robert 455c0b746e5SOllivier Robert /* 456c0b746e5SOllivier Robert * If we haven't had a response in a while, reset the receiver. 457c0b746e5SOllivier Robert */ 4589c2daa00SOllivier Robert if (instance->pollcnt > 0) { 4599c2daa00SOllivier Robert instance->pollcnt--; 460c0b746e5SOllivier Robert } else { 461c0b746e5SOllivier Robert refclock_report(peer, CEVNT_TIMEOUT); 462c0b746e5SOllivier Robert 463c0b746e5SOllivier Robert /* Request the receiver id to trigger a reconfig */ 4649c2daa00SOllivier Robert jupiter_reqonemsg(instance, JUPITER_O_ID); 4659c2daa00SOllivier Robert instance->wantid = 0; 466c0b746e5SOllivier Robert } 467c0b746e5SOllivier Robert 468c0b746e5SOllivier Robert /* 469c0b746e5SOllivier Robert * polled every 64 seconds. Ask jupiter_receive to hand in 470c0b746e5SOllivier Robert * a timestamp. 471c0b746e5SOllivier Robert */ 4729c2daa00SOllivier Robert instance->polled = 1; 473c0b746e5SOllivier Robert pp->polls++; 474c0b746e5SOllivier Robert } 475c0b746e5SOllivier Robert 476c0b746e5SOllivier Robert /* 4779c2daa00SOllivier Robert * jupiter_control - fudge control 4789c2daa00SOllivier Robert */ 4799c2daa00SOllivier Robert static void 4809c2daa00SOllivier Robert jupiter_control( 4819c2daa00SOllivier Robert int unit, /* unit (not used) */ 4822b15cb3dSCy Schubert const struct refclockstat *in, /* input parameters (not used) */ 4839c2daa00SOllivier Robert struct refclockstat *out, /* output parameters (not used) */ 4849c2daa00SOllivier Robert struct peer *peer /* peer structure pointer */ 4859c2daa00SOllivier Robert ) 4869c2daa00SOllivier Robert { 4879c2daa00SOllivier Robert struct refclockproc *pp; 4889c2daa00SOllivier Robert struct instance *instance; 4899c2daa00SOllivier Robert u_char sloppyclockflag; 4909c2daa00SOllivier Robert 4919c2daa00SOllivier Robert pp = peer->procptr; 4922b15cb3dSCy Schubert instance = pp->unitptr; 4939c2daa00SOllivier Robert 4949c2daa00SOllivier Robert DTOLFP(pp->fudgetime2, &instance->limit); 4959c2daa00SOllivier Robert /* Force positive value. */ 4969c2daa00SOllivier Robert if (L_ISNEG(&instance->limit)) 4979c2daa00SOllivier Robert L_NEG(&instance->limit); 4989c2daa00SOllivier Robert 4999c2daa00SOllivier Robert #ifdef HAVE_PPSAPI 5009c2daa00SOllivier Robert instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); 501ea906c41SOllivier Robert jupiter_ppsapi(instance); 5029c2daa00SOllivier Robert #endif /* HAVE_PPSAPI */ 5039c2daa00SOllivier Robert 5049c2daa00SOllivier Robert sloppyclockflag = instance->sloppyclockflag; 5059c2daa00SOllivier Robert instance->sloppyclockflag = pp->sloppyclockflag; 5069c2daa00SOllivier Robert if ((instance->sloppyclockflag & CLK_FLAG2) != 5079c2daa00SOllivier Robert (sloppyclockflag & CLK_FLAG2)) { 5082b15cb3dSCy Schubert jupiter_debug(peer, __func__, 5099c2daa00SOllivier Robert "mode switch: reset receiver"); 5109c2daa00SOllivier Robert jupiter_config(instance); 5119c2daa00SOllivier Robert return; 5129c2daa00SOllivier Robert } 5139c2daa00SOllivier Robert } 5149c2daa00SOllivier Robert 5159c2daa00SOllivier Robert /* 516c0b746e5SOllivier Robert * jupiter_receive - receive gps data 517c0b746e5SOllivier Robert * Gag me! 518c0b746e5SOllivier Robert */ 519c0b746e5SOllivier Robert static void 5209c2daa00SOllivier Robert jupiter_receive(struct recvbuf *rbufp) 521c0b746e5SOllivier Robert { 5222b15cb3dSCy Schubert size_t bpcnt; 5232b15cb3dSCy Schubert int cc, size, ppsret; 5249c2daa00SOllivier Robert time_t last_timecode; 5259c2daa00SOllivier Robert u_int32 laststime; 5262b15cb3dSCy Schubert const char *cp; 5279c2daa00SOllivier Robert u_char *bp; 5289c2daa00SOllivier Robert u_short *sp; 5299c2daa00SOllivier Robert struct jid *ip; 5309c2daa00SOllivier Robert struct jheader *hp; 5319c2daa00SOllivier Robert struct peer *peer; 5329c2daa00SOllivier Robert struct refclockproc *pp; 5339c2daa00SOllivier Robert struct instance *instance; 5349c2daa00SOllivier Robert l_fp tstamp; 535c0b746e5SOllivier Robert 536c0b746e5SOllivier Robert /* Initialize pointers and read the timecode and timestamp */ 5372b15cb3dSCy Schubert peer = rbufp->recv_peer; 538c0b746e5SOllivier Robert pp = peer->procptr; 5392b15cb3dSCy Schubert instance = pp->unitptr; 540c0b746e5SOllivier Robert 541c0b746e5SOllivier Robert bp = (u_char *)rbufp->recv_buffer; 542c0b746e5SOllivier Robert bpcnt = rbufp->recv_length; 543c0b746e5SOllivier Robert 544c0b746e5SOllivier Robert /* This shouldn't happen */ 5459c2daa00SOllivier Robert if (bpcnt > sizeof(instance->sbuf) - instance->ssize) 5469c2daa00SOllivier Robert bpcnt = sizeof(instance->sbuf) - instance->ssize; 547c0b746e5SOllivier Robert 548c0b746e5SOllivier Robert /* Append to input buffer */ 5499c2daa00SOllivier Robert memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); 5509c2daa00SOllivier Robert instance->ssize += bpcnt; 551c0b746e5SOllivier Robert 5529c2daa00SOllivier Robert /* While there's at least a header and we parse an intact message */ 5532b15cb3dSCy Schubert while (instance->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { 5549c2daa00SOllivier Robert instance->pollcnt = 2; 5559c2daa00SOllivier Robert 5569c2daa00SOllivier Robert tstamp = rbufp->recv_time; 5579c2daa00SOllivier Robert hp = (struct jheader *)instance->sbuf; 558c0b746e5SOllivier Robert sp = (u_short *)(hp + 1); 559c0b746e5SOllivier Robert size = cc - sizeof(*hp); 560c0b746e5SOllivier Robert switch (getshort(hp->id)) { 561c0b746e5SOllivier Robert 562c0b746e5SOllivier Robert case JUPITER_O_PULSE: 563c0b746e5SOllivier Robert if (size != sizeof(struct jpulse)) { 5642b15cb3dSCy Schubert jupiter_debug(peer, __func__, 5652b15cb3dSCy Schubert "pulse: len %d != %u", 566c0b746e5SOllivier Robert size, (int)sizeof(struct jpulse)); 567c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 568c0b746e5SOllivier Robert break; 569c0b746e5SOllivier Robert } 570c0b746e5SOllivier Robert 571c0b746e5SOllivier Robert /* 572c0b746e5SOllivier Robert * There appears to be a firmware bug related 573c0b746e5SOllivier Robert * to the pulse message; in addition to the one 574c0b746e5SOllivier Robert * per second messages, we get an extra pulse 575c0b746e5SOllivier Robert * message once an hour (on the anniversary of 576c0b746e5SOllivier Robert * the cold start). It seems to come 200 ms 577c0b746e5SOllivier Robert * after the one requested. So if we've seen a 578c0b746e5SOllivier Robert * pulse message in the last 210 ms, we skip 579c0b746e5SOllivier Robert * this one. 580c0b746e5SOllivier Robert */ 5819c2daa00SOllivier Robert laststime = instance->stime; 5829c2daa00SOllivier Robert instance->stime = DS2UI(((struct jpulse *)sp)->stime); 5839c2daa00SOllivier Robert if (laststime != 0 && instance->stime - laststime <= 21) { 5842b15cb3dSCy Schubert jupiter_debug(peer, __func__, 5859c2daa00SOllivier Robert "avoided firmware bug (stime %.2f, laststime %.2f)", 5869c2daa00SOllivier Robert (double)instance->stime * 0.01, (double)laststime * 0.01); 587c0b746e5SOllivier Robert break; 588c0b746e5SOllivier Robert } 589c0b746e5SOllivier Robert 590c0b746e5SOllivier Robert /* Retrieve pps timestamp */ 5919c2daa00SOllivier Robert ppsret = jupiter_pps(instance); 5929c2daa00SOllivier Robert 5939c2daa00SOllivier Robert /* 5949c2daa00SOllivier Robert * Add one second if msg received early 5959c2daa00SOllivier Robert * (i.e. before limit, a.k.a. fudgetime2) in 5969c2daa00SOllivier Robert * the second. 5979c2daa00SOllivier Robert */ 5989c2daa00SOllivier Robert L_SUB(&tstamp, &pp->lastrec); 5999c2daa00SOllivier Robert if (!L_ISGEQ(&tstamp, &instance->limit)) 6009c2daa00SOllivier Robert ++pp->lastrec.l_ui; 601c0b746e5SOllivier Robert 602c0b746e5SOllivier Robert /* Parse timecode (even when there's no pps) */ 6039c2daa00SOllivier Robert last_timecode = instance->timecode; 6049c2daa00SOllivier Robert if ((cp = jupiter_parse_t(instance, sp)) != NULL) { 6052b15cb3dSCy Schubert jupiter_debug(peer, __func__, 6062b15cb3dSCy Schubert "pulse: %s", cp); 607c0b746e5SOllivier Robert break; 608c0b746e5SOllivier Robert } 609c0b746e5SOllivier Robert 610c0b746e5SOllivier Robert /* Bail if we didn't get a pps timestamp */ 611c0b746e5SOllivier Robert if (ppsret) 612c0b746e5SOllivier Robert break; 613c0b746e5SOllivier Robert 614c0b746e5SOllivier Robert /* Bail if we don't have the last timecode yet */ 615c0b746e5SOllivier Robert if (last_timecode == 0) 616c0b746e5SOllivier Robert break; 617c0b746e5SOllivier Robert 618c0b746e5SOllivier Robert /* Add the new sample to a median filter */ 6192b15cb3dSCy Schubert tstamp.l_ui = JAN_1970 + (u_int32)last_timecode; 6209c2daa00SOllivier Robert tstamp.l_uf = 0; 6219c2daa00SOllivier Robert 6229c2daa00SOllivier Robert refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); 623c0b746e5SOllivier Robert 624c0b746e5SOllivier Robert /* 625c0b746e5SOllivier Robert * The clock will blurt a timecode every second 626c0b746e5SOllivier Robert * but we only want one when polled. If we 627c0b746e5SOllivier Robert * havn't been polled, bail out. 628c0b746e5SOllivier Robert */ 6299c2daa00SOllivier Robert if (!instance->polled) 630c0b746e5SOllivier Robert break; 6319c2daa00SOllivier Robert instance->polled = 0; 632c0b746e5SOllivier Robert 633c0b746e5SOllivier Robert /* 634c0b746e5SOllivier Robert * It's a live one! Remember this time. 635c0b746e5SOllivier Robert */ 636c0b746e5SOllivier Robert 6379c2daa00SOllivier Robert pp->lastref = pp->lastrec; 638c0b746e5SOllivier Robert refclock_receive(peer); 639c0b746e5SOllivier Robert 640c0b746e5SOllivier Robert /* 6419c2daa00SOllivier Robert * If we get here - what we got from the clock is 6429c2daa00SOllivier Robert * OK, so say so 6439c2daa00SOllivier Robert */ 6449c2daa00SOllivier Robert refclock_report(peer, CEVNT_NOMINAL); 6459c2daa00SOllivier Robert 6469c2daa00SOllivier Robert /* 647c0b746e5SOllivier Robert * We have succeeded in answering the poll. 648c0b746e5SOllivier Robert * Turn off the flag and return 649c0b746e5SOllivier Robert */ 6509c2daa00SOllivier Robert instance->polled = 0; 6519c2daa00SOllivier Robert break; 6529c2daa00SOllivier Robert 6539c2daa00SOllivier Robert case JUPITER_O_GPOS: 6549c2daa00SOllivier Robert if (size != sizeof(struct jgpos)) { 6552b15cb3dSCy Schubert jupiter_debug(peer, __func__, 6562b15cb3dSCy Schubert "gpos: len %d != %u", 6579c2daa00SOllivier Robert size, (int)sizeof(struct jgpos)); 6589c2daa00SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 6599c2daa00SOllivier Robert break; 6609c2daa00SOllivier Robert } 6619c2daa00SOllivier Robert 6629c2daa00SOllivier Robert if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { 6632b15cb3dSCy Schubert jupiter_debug(peer, __func__, 6642b15cb3dSCy Schubert "gpos: %s", cp); 6659c2daa00SOllivier Robert break; 6669c2daa00SOllivier Robert } 667c0b746e5SOllivier Robert break; 668c0b746e5SOllivier Robert 669c0b746e5SOllivier Robert case JUPITER_O_ID: 670c0b746e5SOllivier Robert if (size != sizeof(struct jid)) { 6712b15cb3dSCy Schubert jupiter_debug(peer, __func__, 6722b15cb3dSCy Schubert "id: len %d != %u", 673c0b746e5SOllivier Robert size, (int)sizeof(struct jid)); 674c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 675c0b746e5SOllivier Robert break; 676c0b746e5SOllivier Robert } 677c0b746e5SOllivier Robert /* 678c0b746e5SOllivier Robert * If we got this message because the Jupiter 6799c2daa00SOllivier Robert * just powered instance, it needs to be reconfigured. 680c0b746e5SOllivier Robert */ 681c0b746e5SOllivier Robert ip = (struct jid *)sp; 6822b15cb3dSCy Schubert jupiter_debug(peer, __func__, 6832b15cb3dSCy Schubert "%s chan ver %s, %s (%s)", 684c0b746e5SOllivier Robert ip->chans, ip->vers, ip->date, ip->opts); 685c0b746e5SOllivier Robert msyslog(LOG_DEBUG, 686ea906c41SOllivier Robert "jupiter_receive: %s chan ver %s, %s (%s)", 687c0b746e5SOllivier Robert ip->chans, ip->vers, ip->date, ip->opts); 6889c2daa00SOllivier Robert if (instance->wantid) 6899c2daa00SOllivier Robert instance->wantid = 0; 690c0b746e5SOllivier Robert else { 6912b15cb3dSCy Schubert jupiter_debug(peer, __func__, "reset receiver"); 6929c2daa00SOllivier Robert jupiter_config(instance); 6939c2daa00SOllivier Robert /* 6949c2daa00SOllivier Robert * Restore since jupiter_config() just 6959c2daa00SOllivier Robert * zeroed it 6969c2daa00SOllivier Robert */ 6979c2daa00SOllivier Robert instance->ssize = cc; 698c0b746e5SOllivier Robert } 699c0b746e5SOllivier Robert break; 700c0b746e5SOllivier Robert 701c0b746e5SOllivier Robert default: 7022b15cb3dSCy Schubert jupiter_debug(peer, __func__, "unknown message id %d", 703c0b746e5SOllivier Robert getshort(hp->id)); 704c0b746e5SOllivier Robert break; 705c0b746e5SOllivier Robert } 7069c2daa00SOllivier Robert instance->ssize -= cc; 7079c2daa00SOllivier Robert if (instance->ssize < 0) { 708c0b746e5SOllivier Robert fprintf(stderr, "jupiter_recv: negative ssize!\n"); 709c0b746e5SOllivier Robert abort(); 7109c2daa00SOllivier Robert } else if (instance->ssize > 0) 7119c2daa00SOllivier Robert memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); 712c0b746e5SOllivier Robert } 713c0b746e5SOllivier Robert } 714c0b746e5SOllivier Robert 7152b15cb3dSCy Schubert static const char * 7169c2daa00SOllivier Robert jupiter_parse_t(struct instance *instance, u_short *sp) 717c0b746e5SOllivier Robert { 7189c2daa00SOllivier Robert struct tm *tm; 7199c2daa00SOllivier Robert char *cp; 7209c2daa00SOllivier Robert struct jpulse *jp; 7219c2daa00SOllivier Robert u_int32 sweek; 7229c2daa00SOllivier Robert time_t last_timecode; 7239c2daa00SOllivier Robert u_short flags; 724c0b746e5SOllivier Robert 725c0b746e5SOllivier Robert jp = (struct jpulse *)sp; 726c0b746e5SOllivier Robert 727c0b746e5SOllivier Robert /* The timecode is presented as seconds into the current GPS week */ 7289c2daa00SOllivier Robert sweek = DS2UI(jp->sweek) % WEEKSECS; 729c0b746e5SOllivier Robert 730c0b746e5SOllivier Robert /* 731c0b746e5SOllivier Robert * If we don't know the current GPS week, calculate it from the 732c0b746e5SOllivier Robert * current time. (It's too bad they didn't include this 733c0b746e5SOllivier Robert * important value in the pulse message). We'd like to pick it 734c0b746e5SOllivier Robert * up from one of the other messages like gpos or chan but they 735c0b746e5SOllivier Robert * don't appear to be synchronous with time keeping and changes 736c0b746e5SOllivier Robert * too soon (something like 10 seconds before the new GPS 737c0b746e5SOllivier Robert * week). 738c0b746e5SOllivier Robert * 739c0b746e5SOllivier Robert * If we already know the current GPS week, increment it when 740c0b746e5SOllivier Robert * we wrap into a new week. 741c0b746e5SOllivier Robert */ 7429c2daa00SOllivier Robert if (instance->gweek == 0) { 7439c2daa00SOllivier Robert if (!instance->gpos_gweek) { 7449c2daa00SOllivier Robert return ("jupiter_parse_t: Unknown gweek"); 7459c2daa00SOllivier Robert } 7469c2daa00SOllivier Robert 7479c2daa00SOllivier Robert instance->gweek = instance->gpos_gweek; 7489c2daa00SOllivier Robert 7499c2daa00SOllivier Robert /* 7509c2daa00SOllivier Robert * Fix warps. GPOS has GPS time and PULSE has UTC. 7519c2daa00SOllivier Robert * Plus, GPOS need not be completely in synch with 7529c2daa00SOllivier Robert * the PPS signal. 7539c2daa00SOllivier Robert */ 7549c2daa00SOllivier Robert if (instance->gpos_sweek >= sweek) { 7559c2daa00SOllivier Robert if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) 7569c2daa00SOllivier Robert ++instance->gweek; 7579c2daa00SOllivier Robert } 7589c2daa00SOllivier Robert else { 7599c2daa00SOllivier Robert if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) 7609c2daa00SOllivier Robert --instance->gweek; 7619c2daa00SOllivier Robert } 7629c2daa00SOllivier Robert } 7639c2daa00SOllivier Robert else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { 7649c2daa00SOllivier Robert ++instance->gweek; 7652b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 7662b15cb3dSCy Schubert "NEW gps week %u", instance->gweek); 767c0b746e5SOllivier Robert } 768c0b746e5SOllivier Robert 769c0b746e5SOllivier Robert /* 770c0b746e5SOllivier Robert * See if the sweek stayed the same (this happens when there is 771c0b746e5SOllivier Robert * no pps pulse). 772c0b746e5SOllivier Robert * 773c0b746e5SOllivier Robert * Otherwise, look for time warps: 774c0b746e5SOllivier Robert * 775c0b746e5SOllivier Robert * - we have stored at least one lastsweek and 776c0b746e5SOllivier Robert * - the sweek didn't increase by one and 777c0b746e5SOllivier Robert * - we didn't wrap to a new GPS week 778c0b746e5SOllivier Robert * 779c0b746e5SOllivier Robert * Then we warped. 780c0b746e5SOllivier Robert */ 7819c2daa00SOllivier Robert if (instance->lastsweek == sweek) 7822b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 7832b15cb3dSCy Schubert "gps sweek not incrementing (%d)", 784c0b746e5SOllivier Robert sweek); 7859c2daa00SOllivier Robert else if (instance->lastsweek != 2 * WEEKSECS && 7869c2daa00SOllivier Robert instance->lastsweek + 1 != sweek && 7879c2daa00SOllivier Robert !(sweek == 0 && instance->lastsweek == WEEKSECS - 1)) 7882b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 7892b15cb3dSCy Schubert "gps sweek jumped (was %d, now %d)", 7909c2daa00SOllivier Robert instance->lastsweek, sweek); 7919c2daa00SOllivier Robert instance->lastsweek = sweek; 792c0b746e5SOllivier Robert 793c0b746e5SOllivier Robert /* This timecode describes next pulse */ 7949c2daa00SOllivier Robert last_timecode = instance->timecode; 7959c2daa00SOllivier Robert instance->timecode = 7969c2daa00SOllivier Robert GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; 797c0b746e5SOllivier Robert 798c0b746e5SOllivier Robert if (last_timecode == 0) 799c0b746e5SOllivier Robert /* XXX debugging */ 8002b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 8012b15cb3dSCy Schubert "UTC <none> (gweek/sweek %u/%u)", 8029c2daa00SOllivier Robert instance->gweek, sweek); 803c0b746e5SOllivier Robert else { 804c0b746e5SOllivier Robert /* XXX debugging */ 8059c2daa00SOllivier Robert tm = gmtime(&last_timecode); 806c0b746e5SOllivier Robert cp = asctime(tm); 807c0b746e5SOllivier Robert 8082b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 8092b15cb3dSCy Schubert "UTC %.24s (gweek/sweek %u/%u)", 8109c2daa00SOllivier Robert cp, instance->gweek, sweek); 811c0b746e5SOllivier Robert 812c0b746e5SOllivier Robert /* Billboard last_timecode (which is now the current time) */ 8139c2daa00SOllivier Robert instance->peer->procptr->year = tm->tm_year + 1900; 8149c2daa00SOllivier Robert instance->peer->procptr->day = tm->tm_yday + 1; 8159c2daa00SOllivier Robert instance->peer->procptr->hour = tm->tm_hour; 8169c2daa00SOllivier Robert instance->peer->procptr->minute = tm->tm_min; 8179c2daa00SOllivier Robert instance->peer->procptr->second = tm->tm_sec; 818c0b746e5SOllivier Robert } 819c0b746e5SOllivier Robert 820c0b746e5SOllivier Robert flags = getshort(jp->flags); 821c0b746e5SOllivier Robert 822c0b746e5SOllivier Robert /* Toss if not designated "valid" by the gps */ 823c0b746e5SOllivier Robert if ((flags & JUPITER_O_PULSE_VALID) == 0) { 8249c2daa00SOllivier Robert refclock_report(instance->peer, CEVNT_BADTIME); 825c0b746e5SOllivier Robert return ("time mark not valid"); 826c0b746e5SOllivier Robert } 827c0b746e5SOllivier Robert 828c0b746e5SOllivier Robert /* We better be sync'ed to UTC... */ 829c0b746e5SOllivier Robert if ((flags & JUPITER_O_PULSE_UTC) == 0) { 8309c2daa00SOllivier Robert refclock_report(instance->peer, CEVNT_BADTIME); 831c0b746e5SOllivier Robert return ("time mark not sync'ed to UTC"); 832c0b746e5SOllivier Robert } 833c0b746e5SOllivier Robert 834c0b746e5SOllivier Robert return (NULL); 835c0b746e5SOllivier Robert } 836c0b746e5SOllivier Robert 8372b15cb3dSCy Schubert static const char * 8389c2daa00SOllivier Robert jupiter_parse_gpos(struct instance *instance, u_short *sp) 839c0b746e5SOllivier Robert { 8409c2daa00SOllivier Robert struct jgpos *jg; 8419c2daa00SOllivier Robert time_t t; 8429c2daa00SOllivier Robert struct tm *tm; 8439c2daa00SOllivier Robert char *cp; 844c0b746e5SOllivier Robert 8459c2daa00SOllivier Robert jg = (struct jgpos *)sp; 846c0b746e5SOllivier Robert 8479c2daa00SOllivier Robert if (jg->navval != 0) { 848c0b746e5SOllivier Robert /* 8499c2daa00SOllivier Robert * Solution not valid. Use caution and refuse 8509c2daa00SOllivier Robert * to determine GPS week from this message. 851c0b746e5SOllivier Robert */ 8529c2daa00SOllivier Robert instance->gpos_gweek = 0; 8539c2daa00SOllivier Robert instance->gpos_sweek = 0; 8549c2daa00SOllivier Robert return ("Navigation solution not valid"); 855c0b746e5SOllivier Robert } 856c0b746e5SOllivier Robert 8579c2daa00SOllivier Robert instance->gpos_sweek = DS2UI(jg->sweek); 858f391d6bcSXin LI instance->gpos_gweek = get_full_week(get_base_week(), 859f391d6bcSXin LI getshort(jg->gweek)); 860f391d6bcSXin LI 861f391d6bcSXin LI /* according to the protocol spec, the seconds-in-week cannot 862f391d6bcSXin LI * exceed the nominal value: Is it really necessary to normalise 863f391d6bcSXin LI * the seconds??? 864f391d6bcSXin LI */ 8659c2daa00SOllivier Robert while(instance->gpos_sweek >= WEEKSECS) { 8669c2daa00SOllivier Robert instance->gpos_sweek -= WEEKSECS; 8679c2daa00SOllivier Robert ++instance->gpos_gweek; 868c0b746e5SOllivier Robert } 8699c2daa00SOllivier Robert instance->gweek = 0; 870c0b746e5SOllivier Robert 8719c2daa00SOllivier Robert t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; 8729c2daa00SOllivier Robert tm = gmtime(&t); 8739c2daa00SOllivier Robert cp = asctime(tm); 874c0b746e5SOllivier Robert 8752b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 8762b15cb3dSCy Schubert "GPS %.24s (gweek/sweek %u/%u)", 8779c2daa00SOllivier Robert cp, instance->gpos_gweek, instance->gpos_sweek); 8789c2daa00SOllivier Robert return (NULL); 879c0b746e5SOllivier Robert } 880c0b746e5SOllivier Robert 881c0b746e5SOllivier Robert /* 882c0b746e5SOllivier Robert * jupiter_debug - print debug messages 883c0b746e5SOllivier Robert */ 884c0b746e5SOllivier Robert static void 8852b15cb3dSCy Schubert jupiter_debug( 8862b15cb3dSCy Schubert struct peer * peer, 8872b15cb3dSCy Schubert const char * function, 8882b15cb3dSCy Schubert const char * fmt, 8892b15cb3dSCy Schubert ... 8902b15cb3dSCy Schubert ) 891c0b746e5SOllivier Robert { 8929c2daa00SOllivier Robert char buffer[200]; 893c0b746e5SOllivier Robert va_list ap; 894c0b746e5SOllivier Robert 895c0b746e5SOllivier Robert va_start(ap, fmt); 896c0b746e5SOllivier Robert /* 897c0b746e5SOllivier Robert * Print debug message to stdout 898c0b746e5SOllivier Robert * In the future, we may want to get get more creative... 899c0b746e5SOllivier Robert */ 9002b15cb3dSCy Schubert mvsnprintf(buffer, sizeof(buffer), fmt, ap); 9012b15cb3dSCy Schubert record_clock_stats(&peer->srcadr, buffer); 902ea906c41SOllivier Robert #ifdef DEBUG 9039c2daa00SOllivier Robert if (debug) { 9042b15cb3dSCy Schubert printf("%s: %s\n", function, buffer); 9059c2daa00SOllivier Robert fflush(stdout); 9069c2daa00SOllivier Robert } 907ea906c41SOllivier Robert #endif 908c0b746e5SOllivier Robert 909c0b746e5SOllivier Robert va_end(ap); 910c0b746e5SOllivier Robert } 911c0b746e5SOllivier Robert 912c0b746e5SOllivier Robert /* Checksum and transmit a message to the Jupiter */ 913c0b746e5SOllivier Robert static char * 9149c2daa00SOllivier Robert jupiter_send(struct instance *instance, struct jheader *hp) 915c0b746e5SOllivier Robert { 9169c2daa00SOllivier Robert u_int len, size; 9172b15cb3dSCy Schubert ssize_t cc; 9189c2daa00SOllivier Robert u_short *sp; 919c0b746e5SOllivier Robert static char errstr[132]; 920c0b746e5SOllivier Robert 921c0b746e5SOllivier Robert size = sizeof(*hp); 922c0b746e5SOllivier Robert hp->hsum = putshort(jupiter_cksum((u_short *)hp, 923c0b746e5SOllivier Robert (size / sizeof(u_short)) - 1)); 924c0b746e5SOllivier Robert len = getshort(hp->len); 925c0b746e5SOllivier Robert if (len > 0) { 926c0b746e5SOllivier Robert sp = (u_short *)(hp + 1); 927c0b746e5SOllivier Robert sp[len] = putshort(jupiter_cksum(sp, len)); 928c0b746e5SOllivier Robert size += (len + 1) * sizeof(u_short); 929c0b746e5SOllivier Robert } 930c0b746e5SOllivier Robert 9319c2daa00SOllivier Robert if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { 9322b15cb3dSCy Schubert msnprintf(errstr, sizeof(errstr), "write: %m"); 933c0b746e5SOllivier Robert return (errstr); 9342b15cb3dSCy Schubert } else if (cc != (int)size) { 9352b15cb3dSCy Schubert snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size); 936c0b746e5SOllivier Robert return (errstr); 937c0b746e5SOllivier Robert } 938c0b746e5SOllivier Robert return (NULL); 939c0b746e5SOllivier Robert } 940c0b746e5SOllivier Robert 941c0b746e5SOllivier Robert /* Request periodic message output */ 942c0b746e5SOllivier Robert static struct { 943c0b746e5SOllivier Robert struct jheader jheader; 944c0b746e5SOllivier Robert struct jrequest jrequest; 945c0b746e5SOllivier Robert } reqmsg = { 946c0b746e5SOllivier Robert { putshort(JUPITER_SYNC), 0, 947c0b746e5SOllivier Robert putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 948ea906c41SOllivier Robert 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 949ea906c41SOllivier Robert JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 }, 950c0b746e5SOllivier Robert { 0, 0, 0, 0 } 951c0b746e5SOllivier Robert }; 952c0b746e5SOllivier Robert 953c0b746e5SOllivier Robert /* An interval of zero means to output on trigger */ 954c0b746e5SOllivier Robert static void 9559c2daa00SOllivier Robert jupiter_reqmsg(struct instance *instance, u_int id, 9569c2daa00SOllivier Robert u_int interval) 957c0b746e5SOllivier Robert { 9589c2daa00SOllivier Robert struct jheader *hp; 9599c2daa00SOllivier Robert struct jrequest *rp; 9609c2daa00SOllivier Robert char *cp; 961c0b746e5SOllivier Robert 962c0b746e5SOllivier Robert hp = &reqmsg.jheader; 963c0b746e5SOllivier Robert hp->id = putshort(id); 964c0b746e5SOllivier Robert rp = &reqmsg.jrequest; 965c0b746e5SOllivier Robert rp->trigger = putshort(interval == 0); 966c0b746e5SOllivier Robert rp->interval = putshort(interval); 9679c2daa00SOllivier Robert if ((cp = jupiter_send(instance, hp)) != NULL) 9682b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 969c0b746e5SOllivier Robert } 970c0b746e5SOllivier Robert 971c0b746e5SOllivier Robert /* Cancel periodic message output */ 972c0b746e5SOllivier Robert static struct jheader canmsg = { 973c0b746e5SOllivier Robert putshort(JUPITER_SYNC), 0, 0, 0, 974ea906c41SOllivier Robert JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC, 975c0b746e5SOllivier Robert 0 976c0b746e5SOllivier Robert }; 977c0b746e5SOllivier Robert 978c0b746e5SOllivier Robert static void 9799c2daa00SOllivier Robert jupiter_canmsg(struct instance *instance, u_int id) 980c0b746e5SOllivier Robert { 9819c2daa00SOllivier Robert struct jheader *hp; 9829c2daa00SOllivier Robert char *cp; 983c0b746e5SOllivier Robert 984c0b746e5SOllivier Robert hp = &canmsg; 985c0b746e5SOllivier Robert hp->id = putshort(id); 9869c2daa00SOllivier Robert if ((cp = jupiter_send(instance, hp)) != NULL) 9872b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 988c0b746e5SOllivier Robert } 989c0b746e5SOllivier Robert 990c0b746e5SOllivier Robert /* Request a single message output */ 991c0b746e5SOllivier Robert static struct jheader reqonemsg = { 992c0b746e5SOllivier Robert putshort(JUPITER_SYNC), 0, 0, 0, 993ea906c41SOllivier Robert JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY, 994c0b746e5SOllivier Robert 0 995c0b746e5SOllivier Robert }; 996c0b746e5SOllivier Robert 997c0b746e5SOllivier Robert static void 9989c2daa00SOllivier Robert jupiter_reqonemsg(struct instance *instance, u_int id) 999c0b746e5SOllivier Robert { 10009c2daa00SOllivier Robert struct jheader *hp; 10019c2daa00SOllivier Robert char *cp; 1002c0b746e5SOllivier Robert 1003c0b746e5SOllivier Robert hp = &reqonemsg; 1004c0b746e5SOllivier Robert hp->id = putshort(id); 10059c2daa00SOllivier Robert if ((cp = jupiter_send(instance, hp)) != NULL) 10062b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 1007c0b746e5SOllivier Robert } 1008c0b746e5SOllivier Robert 1009c0b746e5SOllivier Robert /* Set the platform dynamics */ 1010c0b746e5SOllivier Robert static struct { 1011c0b746e5SOllivier Robert struct jheader jheader; 1012c0b746e5SOllivier Robert struct jplat jplat; 1013c0b746e5SOllivier Robert } platmsg = { 1014c0b746e5SOllivier Robert { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 1015c0b746e5SOllivier Robert putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 1016ea906c41SOllivier Robert JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 }, 1017c0b746e5SOllivier Robert { 0, 0, 0 } 1018c0b746e5SOllivier Robert }; 1019c0b746e5SOllivier Robert 1020c0b746e5SOllivier Robert static void 10219c2daa00SOllivier Robert jupiter_platform(struct instance *instance, u_int platform) 1022c0b746e5SOllivier Robert { 10239c2daa00SOllivier Robert struct jheader *hp; 10249c2daa00SOllivier Robert struct jplat *pp; 10259c2daa00SOllivier Robert char *cp; 1026c0b746e5SOllivier Robert 1027c0b746e5SOllivier Robert hp = &platmsg.jheader; 1028c0b746e5SOllivier Robert pp = &platmsg.jplat; 1029c0b746e5SOllivier Robert pp->platform = putshort(platform); 10309c2daa00SOllivier Robert if ((cp = jupiter_send(instance, hp)) != NULL) 10312b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "%u: %s", platform, cp); 1032c0b746e5SOllivier Robert } 1033c0b746e5SOllivier Robert 1034c0b746e5SOllivier Robert /* Checksum "len" shorts */ 1035c0b746e5SOllivier Robert static u_short 10369c2daa00SOllivier Robert jupiter_cksum(u_short *sp, u_int len) 1037c0b746e5SOllivier Robert { 10389c2daa00SOllivier Robert u_short sum, x; 1039c0b746e5SOllivier Robert 1040c0b746e5SOllivier Robert sum = 0; 1041c0b746e5SOllivier Robert while (len-- > 0) { 1042c0b746e5SOllivier Robert x = *sp++; 1043c0b746e5SOllivier Robert sum += getshort(x); 1044c0b746e5SOllivier Robert } 1045c0b746e5SOllivier Robert return (~sum + 1); 1046c0b746e5SOllivier Robert } 1047c0b746e5SOllivier Robert 1048c0b746e5SOllivier Robert /* Return the size of the next message (or zero if we don't have it all yet) */ 1049c0b746e5SOllivier Robert static int 10509c2daa00SOllivier Robert jupiter_recv(struct instance *instance) 1051c0b746e5SOllivier Robert { 10529c2daa00SOllivier Robert int n, len, size, cc; 10539c2daa00SOllivier Robert struct jheader *hp; 10549c2daa00SOllivier Robert u_char *bp; 10559c2daa00SOllivier Robert u_short *sp; 1056c0b746e5SOllivier Robert 1057c0b746e5SOllivier Robert /* Must have at least a header's worth */ 1058c0b746e5SOllivier Robert cc = sizeof(*hp); 10599c2daa00SOllivier Robert size = instance->ssize; 1060c0b746e5SOllivier Robert if (size < cc) 1061c0b746e5SOllivier Robert return (0); 1062c0b746e5SOllivier Robert 1063c0b746e5SOllivier Robert /* Search for the sync short if missing */ 10649c2daa00SOllivier Robert sp = instance->sbuf; 1065c0b746e5SOllivier Robert hp = (struct jheader *)sp; 1066c0b746e5SOllivier Robert if (getshort(hp->sync) != JUPITER_SYNC) { 1067c0b746e5SOllivier Robert /* Wasn't at the front, sync up */ 10682b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "syncing"); 1069c0b746e5SOllivier Robert bp = (u_char *)sp; 1070c0b746e5SOllivier Robert n = size; 1071c0b746e5SOllivier Robert while (n >= 2) { 1072c0b746e5SOllivier Robert if (bp[0] != (JUPITER_SYNC & 0xff)) { 10739c2daa00SOllivier Robert /* 10742b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 10752b15cb3dSCy Schubert "{0x%x}", bp[0]); 10769c2daa00SOllivier Robert */ 1077c0b746e5SOllivier Robert ++bp; 1078c0b746e5SOllivier Robert --n; 1079c0b746e5SOllivier Robert continue; 1080c0b746e5SOllivier Robert } 1081c0b746e5SOllivier Robert if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 1082c0b746e5SOllivier Robert break; 10839c2daa00SOllivier Robert /* 10842b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, 10852b15cb3dSCy Schubert "{0x%x 0x%x}", bp[0], bp[1]); 10869c2daa00SOllivier Robert */ 1087c0b746e5SOllivier Robert bp += 2; 1088c0b746e5SOllivier Robert n -= 2; 1089c0b746e5SOllivier Robert } 10909c2daa00SOllivier Robert /* 10912b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "\n"); 10929c2daa00SOllivier Robert */ 1093c0b746e5SOllivier Robert /* Shuffle data to front of input buffer */ 1094c0b746e5SOllivier Robert if (n > 0) 1095c0b746e5SOllivier Robert memcpy(sp, bp, n); 1096c0b746e5SOllivier Robert size = n; 10979c2daa00SOllivier Robert instance->ssize = size; 1098c0b746e5SOllivier Robert if (size < cc || hp->sync != JUPITER_SYNC) 1099c0b746e5SOllivier Robert return (0); 1100c0b746e5SOllivier Robert } 1101c0b746e5SOllivier Robert 1102c0b746e5SOllivier Robert if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1103c0b746e5SOllivier Robert getshort(hp->hsum)) { 11042b15cb3dSCy Schubert jupiter_debug(instance->peer, __func__, "bad header checksum!"); 1105c0b746e5SOllivier Robert /* This is drastic but checksum errors should be rare */ 11069c2daa00SOllivier Robert instance->ssize = 0; 1107c0b746e5SOllivier Robert return (0); 1108c0b746e5SOllivier Robert } 1109c0b746e5SOllivier Robert 1110c0b746e5SOllivier Robert /* Check for a payload */ 1111c0b746e5SOllivier Robert len = getshort(hp->len); 1112c0b746e5SOllivier Robert if (len > 0) { 1113c0b746e5SOllivier Robert n = (len + 1) * sizeof(u_short); 1114c0b746e5SOllivier Robert /* Not enough data yet */ 1115c0b746e5SOllivier Robert if (size < cc + n) 1116c0b746e5SOllivier Robert return (0); 1117c0b746e5SOllivier Robert 1118c0b746e5SOllivier Robert /* Check payload checksum */ 1119c0b746e5SOllivier Robert sp = (u_short *)(hp + 1); 1120c0b746e5SOllivier Robert if (jupiter_cksum(sp, len) != getshort(sp[len])) { 11219c2daa00SOllivier Robert jupiter_debug(instance->peer, 11222b15cb3dSCy Schubert __func__, "bad payload checksum!"); 1123c0b746e5SOllivier Robert /* This is drastic but checksum errors should be rare */ 11249c2daa00SOllivier Robert instance->ssize = 0; 1125c0b746e5SOllivier Robert return (0); 1126c0b746e5SOllivier Robert } 1127c0b746e5SOllivier Robert cc += n; 1128c0b746e5SOllivier Robert } 1129c0b746e5SOllivier Robert return (cc); 1130c0b746e5SOllivier Robert } 1131c0b746e5SOllivier Robert 1132f391d6bcSXin LI static u_int 1133f391d6bcSXin LI get_base_week(void) 1134f391d6bcSXin LI { 1135f391d6bcSXin LI static int init_done /* = 0 */; 1136f391d6bcSXin LI static u_int base_week; 1137f391d6bcSXin LI 1138f391d6bcSXin LI /* Get the build date, convert to days since GPS epoch and 1139f391d6bcSXin LI * finally weeks since GPS epoch. Note that the build stamp is 1140f391d6bcSXin LI * trusted once it is fetched -- only dates before the GPS epoch 1141f391d6bcSXin LI * are not permitted. This will permit proper synchronisation 1142f391d6bcSXin LI * for a time range of 1024 weeks starting with 00:00:00 of the 1143f391d6bcSXin LI * last Sunday on or before the build time. 1144f391d6bcSXin LI * 1145f391d6bcSXin LI * If the impossible happens and fetching the build date fails, 1146f391d6bcSXin LI * a 1024-week cycle starting with 2016-01-03 is assumed to 1147f391d6bcSXin LI * avoid catastropic errors. This will work until 2035-08-19. 1148f391d6bcSXin LI */ 1149f391d6bcSXin LI if (!init_done) { 1150f391d6bcSXin LI struct calendar bd; 1151f391d6bcSXin LI if (ntpcal_get_build_date(&bd)) { 1152f391d6bcSXin LI int32_t days = ntpcal_date_to_rd(&bd); 1153f391d6bcSXin LI if (days > RDN_GPS_EPOCH) 1154f391d6bcSXin LI days -= RDN_GPS_EPOCH; 1155f391d6bcSXin LI else 1156f391d6bcSXin LI days = 0; 1157f391d6bcSXin LI base_week = days / 7; 1158f391d6bcSXin LI } else { 1159f391d6bcSXin LI base_week = 1878; /* 2016-01-03, Sunday */ 1160f391d6bcSXin LI msyslog(LOG_ERR, 1161f391d6bcSXin LI "refclock_jupiter: ntpcal_get_build_date() failed: %s", 1162f391d6bcSXin LI "using 2016-01-03 as GPS base!"); 1163f391d6bcSXin LI } 1164f391d6bcSXin LI init_done = 1; 1165f391d6bcSXin LI } 1166f391d6bcSXin LI return base_week; 1167f391d6bcSXin LI } 1168f391d6bcSXin LI 1169f391d6bcSXin LI static u_int 1170f391d6bcSXin LI get_full_week( 1171f391d6bcSXin LI u_int base_week, 1172f391d6bcSXin LI u_int gpos_week 1173f391d6bcSXin LI ) 1174f391d6bcSXin LI { 1175f391d6bcSXin LI /* Periodic extension on base week. Since the period is 1024 1176f391d6bcSXin LI * weeks and we do unsigned arithmetic here, we can do wonderful 1177f391d6bcSXin LI * things with masks and the well-defined overflow behaviour. 1178f391d6bcSXin LI */ 1179f391d6bcSXin LI return base_week + ((gpos_week - base_week) & 1023); 1180f391d6bcSXin LI } 1181f391d6bcSXin LI 11829c2daa00SOllivier Robert #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1183c0b746e5SOllivier Robert int refclock_jupiter_bs; 11849c2daa00SOllivier Robert #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1185