refclock_jupiter.c revision 182007
167754Smsmith/* 267754Smsmith * Copyright (c) 1997, 1998, 2003 367754Smsmith * The Regents of the University of California. All rights reserved. 491116Smsmith * 567754Smsmith * Redistribution and use in source and binary forms, with or without 667754Smsmith * modification, are permitted provided that the following conditions 767754Smsmith * are met: 867754Smsmith * 1. Redistributions of source code must retain the above copyright 967754Smsmith * notice, this list of conditions and the following disclaimer. 1067754Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1167754Smsmith * notice, this list of conditions and the following disclaimer in the 1291116Smsmith * documentation and/or other materials provided with the distribution. 1370243Smsmith * 3. All advertising materials mentioning features or use of this software 1467754Smsmith * must display the following acknowledgement: 1567754Smsmith * This product includes software developed by the University of 1667754Smsmith * California, Lawrence Berkeley Laboratory. 1767754Smsmith * 4. The name of the University may not be used to endorse or promote 1867754Smsmith * products derived from this software without specific prior 1967754Smsmith * written permission. 2067754Smsmith * 2167754Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2267754Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2367754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2467754Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2567754Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2667754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2767754Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2867754Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2967754Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3067754Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3167754Smsmith * SUCH DAMAGE. 3267754Smsmith */ 3367754Smsmith 3467754Smsmith#ifdef HAVE_CONFIG_H 3567754Smsmith# include <config.h> 3667754Smsmith#endif 3767754Smsmith 3867754Smsmith#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) 3967754Smsmith 4067754Smsmith#include "ntpd.h" 4167754Smsmith#include "ntp_io.h" 4267754Smsmith#include "ntp_refclock.h" 4367754Smsmith#include "ntp_unixtime.h" 4467754Smsmith#include "ntp_stdlib.h" 4567754Smsmith 4667754Smsmith#include <stdio.h> 4767754Smsmith#include <ctype.h> 4867754Smsmith 4967754Smsmith#include "jupiter.h" 5067754Smsmith 5167754Smsmith#ifdef HAVE_PPSAPI 5267754Smsmith# include "ppsapi_timepps.h" 5367754Smsmith#endif 5467754Smsmith 5567754Smsmith#ifdef XNTP_BIG_ENDIAN 5667754Smsmith#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 5767754Smsmith#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 5867754Smsmith#else 5967754Smsmith#define getshort(s) (s) 6067754Smsmith#define putshort(s) (s) 6167754Smsmith#endif 6267754Smsmith 6367754Smsmith/* XXX */ 6467754Smsmith#ifdef sun 6567754Smsmithchar *strerror(int); 6667754Smsmith#endif 6767754Smsmith 6867754Smsmith/* 6967754Smsmith * This driver supports the Rockwell Jupiter GPS Receiver board 7067754Smsmith * adapted to precision timing applications. It requires the 7167754Smsmith * ppsclock line discipline or streams module described in the 7267754Smsmith * Line Disciplines and Streams Drivers page. It also requires a 7367754Smsmith * gadget box and 1-PPS level converter, such as described in the 7467754Smsmith * Pulse-per-second (PPS) Signal Interfacing page. 7567754Smsmith * 7667754Smsmith * It may work (with minor modifications) with other Rockwell GPS 7767754Smsmith * receivers such as the CityTracker. 7867754Smsmith */ 7967754Smsmith 8067754Smsmith/* 8167754Smsmith * GPS Definitions 8267754Smsmith */ 8367754Smsmith#define DEVICE "/dev/gps%d" /* device name and unit */ 8467754Smsmith#define SPEED232 B9600 /* baud */ 8567754Smsmith 8667754Smsmith/* 8767754Smsmith * Radio interface parameters 8867754Smsmith */ 8967754Smsmith#define PRECISION (-18) /* precision assumed (about 4 us) */ 9067754Smsmith#define REFID "GPS\0" /* reference id */ 9167754Smsmith#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ 9267754Smsmith#define DEFFUDGETIME 0 /* default fudge time (ms) */ 9367754Smsmith 9467754Smsmith/* Unix timestamp for the GPS epoch: January 6, 1980 */ 9567754Smsmith#define GPS_EPOCH 315964800 9667754Smsmith 9767754Smsmith/* Double short to unsigned int */ 9867754Smsmith#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 9967754Smsmith 10067754Smsmith/* Double short to signed int */ 10167754Smsmith#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 10267754Smsmith 10367754Smsmith/* One week's worth of seconds */ 10467754Smsmith#define WEEKSECS (7 * 24 * 60 * 60) 10567754Smsmith 10667754Smsmith/* 10767754Smsmith * Jupiter unit control structure. 10867754Smsmith */ 10967754Smsmithstruct instance { 11067754Smsmith struct peer *peer; /* peer */ 11167754Smsmith u_int pollcnt; /* poll message counter */ 11267754Smsmith u_int polled; /* Hand in a time sample? */ 11367754Smsmith#ifdef HAVE_PPSAPI 11467754Smsmith pps_params_t pps_params; /* pps parameters */ 11567754Smsmith pps_info_t pps_info; /* last pps data */ 11667754Smsmith pps_handle_t pps_handle; /* pps handle */ 11767754Smsmith u_int assert; /* pps edge to use */ 11867754Smsmith u_int hardpps; /* enable kernel mode */ 11967754Smsmith struct timespec ts; /* last timestamp */ 12067754Smsmith#endif 12167754Smsmith l_fp limit; 12267754Smsmith u_int gpos_gweek; /* Current GPOS GPS week number */ 12367754Smsmith u_int gpos_sweek; /* Current GPOS GPS seconds into week */ 12467754Smsmith u_int gweek; /* current GPS week number */ 12567754Smsmith u_int32 lastsweek; /* last seconds into GPS week */ 12667754Smsmith time_t timecode; /* current ntp timecode */ 12767754Smsmith u_int32 stime; /* used to detect firmware bug */ 12867754Smsmith int wantid; /* don't reconfig on channel id msg */ 12967754Smsmith u_int moving; /* mobile platform? */ 13067754Smsmith u_char sloppyclockflag; /* fudge flags */ 13167754Smsmith u_short sbuf[512]; /* local input buffer */ 13277424Smsmith int ssize; /* space used in sbuf */ 13391116Smsmith}; 13467754Smsmith 13567754Smsmith/* 13667754Smsmith * Function prototypes 13767754Smsmith */ 13867754Smsmithstatic void jupiter_canmsg P((struct instance *, u_int)); 13967754Smsmithstatic u_short jupiter_cksum P((u_short *, u_int)); 14067754Smsmithstatic int jupiter_config P((struct instance *)); 14167754Smsmithstatic void jupiter_debug P((struct peer *, char *, char *, ...)) 14267754Smsmith __attribute__ ((format (printf, 3, 4))); 14367754Smsmithstatic char * jupiter_parse_t P((struct instance *, u_short *)); 14467754Smsmithstatic char * jupiter_parse_gpos P((struct instance *, u_short *)); 14567754Smsmithstatic void jupiter_platform P((struct instance *, u_int)); 14667754Smsmithstatic void jupiter_poll P((int, struct peer *)); 14767754Smsmithstatic void jupiter_control P((int, struct refclockstat *, struct 14867754Smsmith refclockstat *, struct peer *)); 14967754Smsmith#ifdef HAVE_PPSAPI 15067754Smsmithstatic int jupiter_ppsapi P((struct instance *)); 15167754Smsmithstatic int jupiter_pps P((struct instance *)); 15267754Smsmith#endif /* HAVE_PPSAPI */ 15367754Smsmithstatic int jupiter_recv P((struct instance *)); 15467754Smsmithstatic void jupiter_receive P((struct recvbuf *rbufp)); 15567754Smsmithstatic void jupiter_reqmsg P((struct instance *, u_int, u_int)); 15667754Smsmithstatic void jupiter_reqonemsg P((struct instance *, u_int)); 15767754Smsmithstatic char * jupiter_send P((struct instance *, struct jheader *)); 15867754Smsmithstatic void jupiter_shutdown P((int, struct peer *)); 15967754Smsmithstatic int jupiter_start P((int, struct peer *)); 16067754Smsmith 16167754Smsmith/* 16267754Smsmith * Transfer vector 16367754Smsmith */ 16467754Smsmithstruct refclock refclock_jupiter = { 16567754Smsmith jupiter_start, /* start up driver */ 16667754Smsmith jupiter_shutdown, /* shut down driver */ 16767754Smsmith jupiter_poll, /* transmit poll message */ 16867754Smsmith jupiter_control, /* (clock control) */ 16967754Smsmith noentry, /* (clock init) */ 17091116Smsmith noentry, /* (clock buginfo) */ 17167754Smsmith NOFLAGS /* not used */ 17267754Smsmith}; 17367754Smsmith 17467754Smsmith/* 17567754Smsmith * jupiter_start - open the devices and initialize data for processing 17667754Smsmith */ 17767754Smsmithstatic int 17867754Smsmithjupiter_start( 17967754Smsmith int unit, 18067754Smsmith struct peer *peer 18167754Smsmith ) 18267754Smsmith{ 18367754Smsmith struct refclockproc *pp; 18467754Smsmith struct instance *instance; 18567754Smsmith int fd = -1; 18667754Smsmith char gpsdev[20]; 18767754Smsmith 18867754Smsmith /* 18967754Smsmith * Open serial port 19067754Smsmith */ 19167754Smsmith (void)sprintf(gpsdev, DEVICE, unit); 19267754Smsmith fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 19383174Smsmith if (fd == 0) { 19467754Smsmith jupiter_debug(peer, "jupiter_start", "open %s: %s", 19567754Smsmith gpsdev, strerror(errno)); 19667754Smsmith return (0); 19767754Smsmith } 19867754Smsmith 19967754Smsmith /* Allocate unit structure */ 20067754Smsmith if ((instance = (struct instance *) 20191116Smsmith emalloc(sizeof(struct instance))) == NULL) { 20267754Smsmith (void) close(fd); 20367754Smsmith return (0); 20467754Smsmith } 20567754Smsmith memset((char *)instance, 0, sizeof(struct instance)); 20667754Smsmith instance->peer = peer; 20767754Smsmith pp = peer->procptr; 20867754Smsmith pp->io.clock_recv = jupiter_receive; 20967754Smsmith pp->io.srcclock = (caddr_t)peer; 21067754Smsmith pp->io.datalen = 0; 21167754Smsmith pp->io.fd = fd; 21267754Smsmith if (!io_addclock(&pp->io)) { 21367754Smsmith (void) close(fd); 21467754Smsmith free(instance); 21567754Smsmith return (0); 21667754Smsmith } 21767754Smsmith pp->unitptr = (caddr_t)instance; 21867754Smsmith 21967754Smsmith /* 22067754Smsmith * Initialize miscellaneous variables 22167754Smsmith */ 22267754Smsmith peer->precision = PRECISION; 22367754Smsmith pp->clockdesc = DESCRIPTION; 22467754Smsmith memcpy((char *)&pp->refid, REFID, 4); 22567754Smsmith 22667754Smsmith#ifdef HAVE_PPSAPI 22767754Smsmith instance->assert = 1; 22867754Smsmith instance->hardpps = 0; 22967754Smsmith /* 23087031Smsmith * Start the PPSAPI interface if it is there. Default to use 23167754Smsmith * the assert edge and do not enable the kernel hardpps. 23267754Smsmith */ 23367754Smsmith if (time_pps_create(fd, &instance->pps_handle) < 0) { 23467754Smsmith instance->pps_handle = 0; 23567754Smsmith msyslog(LOG_ERR, 23667754Smsmith "refclock_jupiter: time_pps_create failed: %m"); 23767754Smsmith } 23867754Smsmith else if (!jupiter_ppsapi(instance)) 23967754Smsmith goto clean_up; 24067754Smsmith#endif /* HAVE_PPSAPI */ 24167754Smsmith 24267754Smsmith /* Ensure the receiver is properly configured */ 24367754Smsmith if (!jupiter_config(instance)) 24467754Smsmith goto clean_up; 24567754Smsmith 24667754Smsmith return (1); 24791116Smsmith 24867754Smsmithclean_up: 24967754Smsmith jupiter_shutdown(unit, peer); 25067754Smsmith pp->unitptr = 0; 25167754Smsmith return (0); 25267754Smsmith} 25367754Smsmith 25467754Smsmith/* 25567754Smsmith * jupiter_shutdown - shut down the clock 25667754Smsmith */ 25767754Smsmithstatic void 25867754Smsmithjupiter_shutdown(int unit, struct peer *peer) 25967754Smsmith{ 26067754Smsmith struct instance *instance; 26167754Smsmith struct refclockproc *pp; 26267754Smsmith 26367754Smsmith pp = peer->procptr; 26467754Smsmith instance = (struct instance *)pp->unitptr; 26567754Smsmith if (!instance) 26667754Smsmith return; 26767754Smsmith 26867754Smsmith#ifdef HAVE_PPSAPI 26967754Smsmith if (instance->pps_handle) { 27067754Smsmith time_pps_destroy(instance->pps_handle); 27167754Smsmith instance->pps_handle = 0; 27267754Smsmith } 27367754Smsmith#endif /* HAVE_PPSAPI */ 27467754Smsmith 27567754Smsmith io_closeclock(&pp->io); 27667754Smsmith free(instance); 27767754Smsmith} 27891116Smsmith 27967754Smsmith/* 28091116Smsmith * jupiter_config - Configure the receiver 28167754Smsmith */ 28291116Smsmithstatic int 28391116Smsmithjupiter_config(struct instance *instance) 28467754Smsmith{ 28567754Smsmith jupiter_debug(instance->peer, "jupiter_config", "init receiver"); 28667754Smsmith 28767754Smsmith /* 28867754Smsmith * Initialize the unit variables 28967754Smsmith */ 29067754Smsmith instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; 29167754Smsmith instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); 29267754Smsmith if (instance->moving) 29367754Smsmith jupiter_debug(instance->peer, "jupiter_config", 29491116Smsmith "mobile platform"); 29591116Smsmith 29691116Smsmith instance->pollcnt = 2; 29791116Smsmith instance->polled = 0; 29867754Smsmith instance->gpos_gweek = 0; 29967754Smsmith instance->gpos_sweek = 0; 30067754Smsmith instance->gweek = 0; 30167754Smsmith instance->lastsweek = 2 * WEEKSECS; 30267754Smsmith instance->timecode = 0; 30367754Smsmith instance->stime = 0; 30477424Smsmith instance->ssize = 0; 30577424Smsmith 30691116Smsmith /* Stop outputting all messages */ 30767754Smsmith jupiter_canmsg(instance, JUPITER_ALL); 30867754Smsmith 30991116Smsmith /* Request the receiver id so we can syslog the firmware version */ 31091116Smsmith jupiter_reqonemsg(instance, JUPITER_O_ID); 31191116Smsmith 31291116Smsmith /* Flag that this the id was requested (so we don't get called again) */ 31367754Smsmith instance->wantid = 1; 31467754Smsmith 31567754Smsmith /* Request perodic time mark pulse messages */ 31667754Smsmith jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); 31767754Smsmith 31867754Smsmith /* Request perodic geodetic position status */ 31977424Smsmith jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); 32067754Smsmith 32191116Smsmith /* Set application platform type */ 32267754Smsmith if (instance->moving) 32391116Smsmith jupiter_platform(instance, JUPITER_I_PLAT_MED); 32491116Smsmith else 32591116Smsmith jupiter_platform(instance, JUPITER_I_PLAT_LOW); 32691116Smsmith 32791116Smsmith return (1); 32867754Smsmith} 32967754Smsmith 33067754Smsmith#ifdef HAVE_PPSAPI 33167754Smsmith/* 33267754Smsmith * Initialize PPSAPI 33367754Smsmith */ 33467754Smsmithint 33567754Smsmithjupiter_ppsapi( 33677424Smsmith struct instance *instance /* unit structure pointer */ 33791116Smsmith ) 33867754Smsmith{ 33967754Smsmith int capability; 34067754Smsmith 34167754Smsmith if (time_pps_getcap(instance->pps_handle, &capability) < 0) { 34267754Smsmith msyslog(LOG_ERR, 34367754Smsmith "refclock_jupiter: time_pps_getcap failed: %m"); 34467754Smsmith return (0); 34567754Smsmith } 34667754Smsmith memset(&instance->pps_params, 0, sizeof(pps_params_t)); 34767754Smsmith if (!instance->assert) 34867754Smsmith instance->pps_params.mode = capability & PPS_CAPTURECLEAR; 34967754Smsmith else 35067754Smsmith instance->pps_params.mode = capability & PPS_CAPTUREASSERT; 35167754Smsmith if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 35267754Smsmith msyslog(LOG_ERR, 35367754Smsmith "refclock_jupiter: invalid capture edge %d", 35467754Smsmith instance->assert); 35567754Smsmith return (0); 35667754Smsmith } 35767754Smsmith instance->pps_params.mode |= PPS_TSFMT_TSPEC; 35867754Smsmith if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { 35967754Smsmith msyslog(LOG_ERR, 36067754Smsmith "refclock_jupiter: time_pps_setparams failed: %m"); 36169746Smsmith return (0); 36269746Smsmith } 36385756Smsmith if (instance->hardpps) { 36469746Smsmith if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, 36569746Smsmith instance->pps_params.mode & ~PPS_TSFMT_TSPEC, 36667754Smsmith PPS_TSFMT_TSPEC) < 0) { 36767754Smsmith msyslog(LOG_ERR, 36867754Smsmith "refclock_jupiter: time_pps_kcbind failed: %m"); 36967754Smsmith return (0); 37067754Smsmith } 37167754Smsmith pps_enable = 1; 37277424Smsmith } 37377424Smsmith/* instance->peer->precision = PPS_PRECISION; */ 37467754Smsmith 37587031Smsmith#if DEBUG 37687031Smsmith if (debug) { 37767754Smsmith time_pps_getparams(instance->pps_handle, &instance->pps_params); 37887031Smsmith jupiter_debug(instance->peer, "refclock_jupiter", 37987031Smsmith "pps capability 0x%x version %d mode 0x%x kern %d", 38067754Smsmith capability, instance->pps_params.api_version, 38187031Smsmith instance->pps_params.mode, instance->hardpps); 38267754Smsmith } 38367754Smsmith#endif 38467754Smsmith 38587031Smsmith return (1); 38687031Smsmith} 38767754Smsmith 38867754Smsmith/* 38967754Smsmith * Get PPSAPI timestamps. 39067754Smsmith * 39167754Smsmith * Return 0 on failure and 1 on success. 39267754Smsmith */ 39367754Smsmithstatic int 39467754Smsmithjupiter_pps(struct instance *instance) 39567754Smsmith{ 39667754Smsmith pps_info_t pps_info; 39767754Smsmith struct timespec timeout, ts; 39867754Smsmith double dtemp; 39967754Smsmith l_fp tstmp; 40067754Smsmith 40167754Smsmith /* 40267754Smsmith * Convert the timespec nanoseconds field to ntp l_fp units. 40367754Smsmith */ 40467754Smsmith if (instance->pps_handle == 0) 40567754Smsmith return 1; 40667754Smsmith timeout.tv_sec = 0; 40771867Smsmith timeout.tv_nsec = 0; 40867754Smsmith memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); 40971867Smsmith if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, 41067754Smsmith &timeout) < 0) 41167754Smsmith return 1; 41267754Smsmith if (instance->pps_params.mode & PPS_CAPTUREASSERT) { 41367754Smsmith if (pps_info.assert_sequence == 41467754Smsmith instance->pps_info.assert_sequence) 41577424Smsmith return 1; 41667754Smsmith ts = instance->pps_info.assert_timestamp; 41767754Smsmith } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { 41867754Smsmith if (pps_info.clear_sequence == 41971867Smsmith instance->pps_info.clear_sequence) 42082367Smsmith return 1; 42191116Smsmith ts = instance->pps_info.clear_timestamp; 42291116Smsmith } else { 42367754Smsmith return 1; 42467754Smsmith } 42582367Smsmith if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) 42667754Smsmith return 1; 42782367Smsmith instance->ts = ts; 42880062Smsmith 42971867Smsmith tstmp.l_ui = ts.tv_sec + JAN_1970; 43080062Smsmith dtemp = ts.tv_nsec * FRAC / 1e9; 43180062Smsmith tstmp.l_uf = (u_int32)dtemp; 43280062Smsmith instance->peer->procptr->lastrec = tstmp; 43383174Smsmith return 0; 43480062Smsmith} 43580062Smsmith#endif /* HAVE_PPSAPI */ 43680062Smsmith 43780062Smsmith/* 43880062Smsmith * jupiter_poll - jupiter watchdog routine 43967754Smsmith */ 44071867Smsmithstatic void 44182367Smsmithjupiter_poll(int unit, struct peer *peer) 44271867Smsmith{ 44382367Smsmith struct instance *instance; 44471867Smsmith struct refclockproc *pp; 44571867Smsmith 44671867Smsmith pp = peer->procptr; 44771867Smsmith instance = (struct instance *)pp->unitptr; 44871867Smsmith 44971867Smsmith /* 45067754Smsmith * You don't need to poll this clock. It puts out timecodes 45167754Smsmith * once per second. If asked for a timestamp, take note. 45267754Smsmith * The next time a timecode comes in, it will be fed back. 45367754Smsmith */ 45467754Smsmith 45567754Smsmith /* 45667754Smsmith * If we haven't had a response in a while, reset the receiver. 45767754Smsmith */ 45867754Smsmith if (instance->pollcnt > 0) { 45967754Smsmith instance->pollcnt--; 46067754Smsmith } else { 46167754Smsmith refclock_report(peer, CEVNT_TIMEOUT); 46267754Smsmith 46367754Smsmith /* Request the receiver id to trigger a reconfig */ 46467754Smsmith jupiter_reqonemsg(instance, JUPITER_O_ID); 46567754Smsmith instance->wantid = 0; 46667754Smsmith } 46767754Smsmith 46867754Smsmith /* 46967754Smsmith * polled every 64 seconds. Ask jupiter_receive to hand in 47067754Smsmith * a timestamp. 47167754Smsmith */ 47267754Smsmith instance->polled = 1; 47367754Smsmith pp->polls++; 47467754Smsmith} 47567754Smsmith 47667754Smsmith/* 47767754Smsmith * jupiter_control - fudge control 47867754Smsmith */ 47967754Smsmithstatic void 48067754Smsmithjupiter_control( 48167754Smsmith int unit, /* unit (not used) */ 48267754Smsmith struct refclockstat *in, /* input parameters (not used) */ 48367754Smsmith struct refclockstat *out, /* output parameters (not used) */ 48467754Smsmith struct peer *peer /* peer structure pointer */ 48591116Smsmith ) 48667754Smsmith{ 48791116Smsmith struct refclockproc *pp; 48891116Smsmith struct instance *instance; 48967754Smsmith u_char sloppyclockflag; 49091116Smsmith 49167754Smsmith pp = peer->procptr; 49291116Smsmith instance = (struct instance *)pp->unitptr; 49391116Smsmith 49491116Smsmith DTOLFP(pp->fudgetime2, &instance->limit); 49570243Smsmith /* Force positive value. */ 49669746Smsmith if (L_ISNEG(&instance->limit)) 49777424Smsmith L_NEG(&instance->limit); 49887031Smsmith 49969746Smsmith#ifdef HAVE_PPSAPI 50069746Smsmith instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); 50169746Smsmith jupiter_ppsapi(instance); 50269746Smsmith#endif /* HAVE_PPSAPI */ 50369746Smsmith 50469746Smsmith sloppyclockflag = instance->sloppyclockflag; 50569746Smsmith instance->sloppyclockflag = pp->sloppyclockflag; 50669746Smsmith if ((instance->sloppyclockflag & CLK_FLAG2) != 50791116Smsmith (sloppyclockflag & CLK_FLAG2)) { 50867754Smsmith jupiter_debug(peer, 50991116Smsmith "jupiter_control", 51091116Smsmith "mode switch: reset receiver"); 51191116Smsmith jupiter_config(instance); 51267754Smsmith return; 51367754Smsmith } 51467754Smsmith} 51567754Smsmith 51667754Smsmith/* 51767754Smsmith * jupiter_receive - receive gps data 51867754Smsmith * Gag me! 51967754Smsmith */ 52067754Smsmithstatic void 52167754Smsmithjupiter_receive(struct recvbuf *rbufp) 52267754Smsmith{ 52367754Smsmith int bpcnt, cc, size, ppsret; 52477424Smsmith time_t last_timecode; 52567754Smsmith u_int32 laststime; 52667754Smsmith char *cp; 52784491Smsmith u_char *bp; 52867754Smsmith u_short *sp; 52967754Smsmith struct jid *ip; 53067754Smsmith struct jheader *hp; 53184491Smsmith struct peer *peer; 53267754Smsmith struct refclockproc *pp; 53367754Smsmith struct instance *instance; 53467754Smsmith l_fp tstamp; 53584491Smsmith 53667754Smsmith /* Initialize pointers and read the timecode and timestamp */ 53767754Smsmith peer = (struct peer *)rbufp->recv_srcclock; 53884491Smsmith pp = peer->procptr; 53985756Smsmith instance = (struct instance *)pp->unitptr; 54084491Smsmith 54184491Smsmith bp = (u_char *)rbufp->recv_buffer; 54267754Smsmith bpcnt = rbufp->recv_length; 54384491Smsmith 54467754Smsmith /* This shouldn't happen */ 54567754Smsmith if (bpcnt > sizeof(instance->sbuf) - instance->ssize) 54667754Smsmith bpcnt = sizeof(instance->sbuf) - instance->ssize; 54784491Smsmith 54867754Smsmith /* Append to input buffer */ 54967754Smsmith memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); 55067754Smsmith instance->ssize += bpcnt; 55167754Smsmith 55267754Smsmith /* While there's at least a header and we parse an intact message */ 55384491Smsmith while (instance->ssize > sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { 55467754Smsmith instance->pollcnt = 2; 55567754Smsmith 55667754Smsmith tstamp = rbufp->recv_time; 55784491Smsmith hp = (struct jheader *)instance->sbuf; 55867754Smsmith sp = (u_short *)(hp + 1); 55967754Smsmith size = cc - sizeof(*hp); 56067754Smsmith switch (getshort(hp->id)) { 56167754Smsmith 56267754Smsmith case JUPITER_O_PULSE: 56367754Smsmith if (size != sizeof(struct jpulse)) { 56467754Smsmith jupiter_debug(peer, 56567754Smsmith "jupiter_receive", "pulse: len %d != %u", 56667754Smsmith size, (int)sizeof(struct jpulse)); 56791116Smsmith refclock_report(peer, CEVNT_BADREPLY); 56867754Smsmith break; 56967754Smsmith } 57067754Smsmith 57167754Smsmith /* 57267754Smsmith * There appears to be a firmware bug related 57367754Smsmith * to the pulse message; in addition to the one 57467754Smsmith * per second messages, we get an extra pulse 57567754Smsmith * message once an hour (on the anniversary of 57667754Smsmith * the cold start). It seems to come 200 ms 57767754Smsmith * after the one requested. So if we've seen a 57884491Smsmith * pulse message in the last 210 ms, we skip 57971867Smsmith * this one. 58067754Smsmith */ 58167754Smsmith laststime = instance->stime; 58267754Smsmith instance->stime = DS2UI(((struct jpulse *)sp)->stime); 58391116Smsmith if (laststime != 0 && instance->stime - laststime <= 21) { 58467754Smsmith jupiter_debug(peer, "jupiter_receive", 58591116Smsmith "avoided firmware bug (stime %.2f, laststime %.2f)", 58691116Smsmith (double)instance->stime * 0.01, (double)laststime * 0.01); 58791116Smsmith break; 58867754Smsmith } 58991116Smsmith 59067754Smsmith /* Retrieve pps timestamp */ 59167754Smsmith ppsret = jupiter_pps(instance); 59291116Smsmith 59367754Smsmith /* 59467754Smsmith * Add one second if msg received early 59567754Smsmith * (i.e. before limit, a.k.a. fudgetime2) in 59667754Smsmith * the second. 59767754Smsmith */ 59867754Smsmith L_SUB(&tstamp, &pp->lastrec); 59967754Smsmith if (!L_ISGEQ(&tstamp, &instance->limit)) 60067754Smsmith ++pp->lastrec.l_ui; 60167754Smsmith 60267754Smsmith /* Parse timecode (even when there's no pps) */ 60367754Smsmith last_timecode = instance->timecode; 60467754Smsmith if ((cp = jupiter_parse_t(instance, sp)) != NULL) { 60567754Smsmith jupiter_debug(peer, 60667754Smsmith "jupiter_receive", "pulse: %s", cp); 60767754Smsmith break; 60867754Smsmith } 60967754Smsmith 61067754Smsmith /* Bail if we didn't get a pps timestamp */ 61167754Smsmith if (ppsret) 61267754Smsmith break; 61367754Smsmith 61467754Smsmith /* Bail if we don't have the last timecode yet */ 61567754Smsmith if (last_timecode == 0) 61667754Smsmith break; 61767754Smsmith 61883174Smsmith /* Add the new sample to a median filter */ 61967754Smsmith tstamp.l_ui = JAN_1970 + last_timecode; 62067754Smsmith tstamp.l_uf = 0; 62167754Smsmith 62267754Smsmith refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); 62367754Smsmith 62467754Smsmith /* 62567754Smsmith * The clock will blurt a timecode every second 62667754Smsmith * but we only want one when polled. If we 62767754Smsmith * havn't been polled, bail out. 62867754Smsmith */ 62967754Smsmith if (!instance->polled) 63067754Smsmith break; 63167754Smsmith instance->polled = 0; 63267754Smsmith 63367754Smsmith /* 63467754Smsmith * It's a live one! Remember this time. 63567754Smsmith */ 63667754Smsmith 63767754Smsmith pp->lastref = pp->lastrec; 63887031Smsmith refclock_receive(peer); 63967754Smsmith 64087031Smsmith /* 64167754Smsmith * If we get here - what we got from the clock is 64267754Smsmith * OK, so say so 64367754Smsmith */ 64469746Smsmith refclock_report(peer, CEVNT_NOMINAL); 64567754Smsmith 64667754Smsmith /* 64767754Smsmith * We have succeeded in answering the poll. 64867754Smsmith * Turn off the flag and return 64967754Smsmith */ 65067754Smsmith instance->polled = 0; 65167754Smsmith break; 65267754Smsmith 65367754Smsmith case JUPITER_O_GPOS: 65467754Smsmith if (size != sizeof(struct jgpos)) { 65567754Smsmith jupiter_debug(peer, 65667754Smsmith "jupiter_receive", "gpos: len %d != %u", 65767754Smsmith size, (int)sizeof(struct jgpos)); 65867754Smsmith refclock_report(peer, CEVNT_BADREPLY); 65967754Smsmith break; 66067754Smsmith } 66167754Smsmith 66267754Smsmith if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { 66367754Smsmith jupiter_debug(peer, 66467754Smsmith "jupiter_receive", "gpos: %s", cp); 66567754Smsmith break; 66667754Smsmith } 66767754Smsmith break; 66867754Smsmith 66967754Smsmith case JUPITER_O_ID: 67085756Smsmith if (size != sizeof(struct jid)) { 67185756Smsmith jupiter_debug(peer, 67267754Smsmith "jupiter_receive", "id: len %d != %u", 67385756Smsmith size, (int)sizeof(struct jid)); 67467754Smsmith refclock_report(peer, CEVNT_BADREPLY); 67567754Smsmith break; 67667754Smsmith } 67767754Smsmith /* 67867754Smsmith * If we got this message because the Jupiter 67967754Smsmith * just powered instance, it needs to be reconfigured. 68067754Smsmith */ 68167754Smsmith ip = (struct jid *)sp; 68285756Smsmith jupiter_debug(peer, 68385756Smsmith "jupiter_receive", "%s chan ver %s, %s (%s)", 68485756Smsmith ip->chans, ip->vers, ip->date, ip->opts); 68585756Smsmith msyslog(LOG_DEBUG, 68685756Smsmith "jupiter_receive: %s chan ver %s, %s (%s)", 68767754Smsmith ip->chans, ip->vers, ip->date, ip->opts); 68867754Smsmith if (instance->wantid) 68967754Smsmith instance->wantid = 0; 69067754Smsmith else { 69167754Smsmith jupiter_debug(peer, 69267754Smsmith "jupiter_receive", "reset receiver"); 69367754Smsmith jupiter_config(instance); 69467754Smsmith /* 69567754Smsmith * Restore since jupiter_config() just 69667754Smsmith * zeroed it 69767754Smsmith */ 69867754Smsmith instance->ssize = cc; 69967754Smsmith } 70069746Smsmith break; 70167754Smsmith 70267754Smsmith default: 70369746Smsmith jupiter_debug(peer, 70467754Smsmith "jupiter_receive", "unknown message id %d", 70567754Smsmith getshort(hp->id)); 70667754Smsmith break; 70767754Smsmith } 70867754Smsmith instance->ssize -= cc; 70967754Smsmith if (instance->ssize < 0) { 71067754Smsmith fprintf(stderr, "jupiter_recv: negative ssize!\n"); 71167754Smsmith abort(); 71267754Smsmith } else if (instance->ssize > 0) 71367754Smsmith memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); 71467754Smsmith } 71567754Smsmith} 71667754Smsmith 71767754Smsmithstatic char * 71867754Smsmithjupiter_parse_t(struct instance *instance, u_short *sp) 71967754Smsmith{ 72067754Smsmith struct tm *tm; 72167754Smsmith char *cp; 72267754Smsmith struct jpulse *jp; 72367754Smsmith u_int32 sweek; 72467754Smsmith time_t last_timecode; 72567754Smsmith u_short flags; 72667754Smsmith 72767754Smsmith jp = (struct jpulse *)sp; 72867754Smsmith 72967754Smsmith /* The timecode is presented as seconds into the current GPS week */ 73067754Smsmith sweek = DS2UI(jp->sweek) % WEEKSECS; 73167754Smsmith 73267754Smsmith /* 73367754Smsmith * If we don't know the current GPS week, calculate it from the 73467754Smsmith * current time. (It's too bad they didn't include this 73567754Smsmith * important value in the pulse message). We'd like to pick it 73667754Smsmith * up from one of the other messages like gpos or chan but they 73769450Smsmith * don't appear to be synchronous with time keeping and changes 73867754Smsmith * too soon (something like 10 seconds before the new GPS 73967754Smsmith * week). 74067754Smsmith * 74167754Smsmith * If we already know the current GPS week, increment it when 74267754Smsmith * we wrap into a new week. 74367754Smsmith */ 74467754Smsmith if (instance->gweek == 0) { 74567754Smsmith if (!instance->gpos_gweek) { 74667754Smsmith return ("jupiter_parse_t: Unknown gweek"); 74767754Smsmith } 74867754Smsmith 74967754Smsmith instance->gweek = instance->gpos_gweek; 75067754Smsmith 75167754Smsmith /* 75267754Smsmith * Fix warps. GPOS has GPS time and PULSE has UTC. 75367754Smsmith * Plus, GPOS need not be completely in synch with 75467754Smsmith * the PPS signal. 75567754Smsmith */ 75667754Smsmith if (instance->gpos_sweek >= sweek) { 75767754Smsmith if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) 75867754Smsmith ++instance->gweek; 75967754Smsmith } 76067754Smsmith else { 76167754Smsmith if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) 76267754Smsmith --instance->gweek; 76367754Smsmith } 76467754Smsmith } 76567754Smsmith else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { 76667754Smsmith ++instance->gweek; 76767754Smsmith jupiter_debug(instance->peer, 76867754Smsmith "jupiter_parse_t", "NEW gps week %u", instance->gweek); 76967754Smsmith } 77067754Smsmith 77167754Smsmith /* 77267754Smsmith * See if the sweek stayed the same (this happens when there is 77367754Smsmith * no pps pulse). 77467754Smsmith * 77567754Smsmith * Otherwise, look for time warps: 77667754Smsmith * 77767754Smsmith * - we have stored at least one lastsweek and 77867754Smsmith * - the sweek didn't increase by one and 77967754Smsmith * - we didn't wrap to a new GPS week 78087031Smsmith * 78167754Smsmith * Then we warped. 78287031Smsmith */ 78367754Smsmith if (instance->lastsweek == sweek) 78467754Smsmith jupiter_debug(instance->peer, 78587031Smsmith "jupiter_parse_t", "gps sweek not incrementing (%d)", 78687031Smsmith sweek); 78767754Smsmith else if (instance->lastsweek != 2 * WEEKSECS && 78867754Smsmith instance->lastsweek + 1 != sweek && 78967754Smsmith !(sweek == 0 && instance->lastsweek == WEEKSECS - 1)) 79067754Smsmith jupiter_debug(instance->peer, 79167754Smsmith "jupiter_parse_t", "gps sweek jumped (was %d, now %d)", 79267754Smsmith instance->lastsweek, sweek); 79367754Smsmith instance->lastsweek = sweek; 79467754Smsmith 79567754Smsmith /* This timecode describes next pulse */ 79667754Smsmith last_timecode = instance->timecode; 79767754Smsmith instance->timecode = 79867754Smsmith GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; 79967754Smsmith 80067754Smsmith if (last_timecode == 0) 80167754Smsmith /* XXX debugging */ 80267754Smsmith jupiter_debug(instance->peer, 80367754Smsmith "jupiter_parse_t", "UTC <none> (gweek/sweek %u/%u)", 80467754Smsmith instance->gweek, sweek); 80567754Smsmith else { 80667754Smsmith /* XXX debugging */ 80767754Smsmith tm = gmtime(&last_timecode); 80867754Smsmith cp = asctime(tm); 80967754Smsmith 81067754Smsmith jupiter_debug(instance->peer, 81167754Smsmith "jupiter_parse_t", "UTC %.24s (gweek/sweek %u/%u)", 81267754Smsmith cp, instance->gweek, sweek); 81367754Smsmith 81467754Smsmith /* Billboard last_timecode (which is now the current time) */ 81569746Smsmith instance->peer->procptr->year = tm->tm_year + 1900; 81667754Smsmith instance->peer->procptr->day = tm->tm_yday + 1; 81767754Smsmith instance->peer->procptr->hour = tm->tm_hour; 81867754Smsmith instance->peer->procptr->minute = tm->tm_min; 81967754Smsmith instance->peer->procptr->second = tm->tm_sec; 82067754Smsmith } 82167754Smsmith 82267754Smsmith flags = getshort(jp->flags); 82367754Smsmith 82467754Smsmith /* Toss if not designated "valid" by the gps */ 82567754Smsmith if ((flags & JUPITER_O_PULSE_VALID) == 0) { 82667754Smsmith refclock_report(instance->peer, CEVNT_BADTIME); 82767754Smsmith return ("time mark not valid"); 82867754Smsmith } 82969746Smsmith 83069746Smsmith /* We better be sync'ed to UTC... */ 83169746Smsmith if ((flags & JUPITER_O_PULSE_UTC) == 0) { 83269746Smsmith refclock_report(instance->peer, CEVNT_BADTIME); 83367754Smsmith return ("time mark not sync'ed to UTC"); 83487031Smsmith } 83587031Smsmith 83669746Smsmith return (NULL); 83769746Smsmith} 83867754Smsmith 83969746Smsmithstatic char * 84067754Smsmithjupiter_parse_gpos(struct instance *instance, u_short *sp) 84167754Smsmith{ 84267754Smsmith struct jgpos *jg; 84367754Smsmith time_t t; 84467754Smsmith struct tm *tm; 84567754Smsmith char *cp; 84667754Smsmith 84767754Smsmith jg = (struct jgpos *)sp; 84867754Smsmith 84967754Smsmith if (jg->navval != 0) { 85067754Smsmith /* 85167754Smsmith * Solution not valid. Use caution and refuse 85267754Smsmith * to determine GPS week from this message. 85367754Smsmith */ 85467754Smsmith instance->gpos_gweek = 0; 85567754Smsmith instance->gpos_sweek = 0; 85667754Smsmith return ("Navigation solution not valid"); 85767754Smsmith } 85867754Smsmith 85967754Smsmith instance->gpos_gweek = jg->gweek; 86067754Smsmith instance->gpos_sweek = DS2UI(jg->sweek); 86167754Smsmith while(instance->gpos_sweek >= WEEKSECS) { 86267754Smsmith instance->gpos_sweek -= WEEKSECS; 86367754Smsmith ++instance->gpos_gweek; 86467754Smsmith } 86567754Smsmith instance->gweek = 0; 86667754Smsmith 86767754Smsmith t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; 86867754Smsmith tm = gmtime(&t); 86967754Smsmith cp = asctime(tm); 87067754Smsmith 87167754Smsmith jupiter_debug(instance->peer, 87267754Smsmith "jupiter_parse_g", "GPS %.24s (gweek/sweek %u/%u)", 87369450Smsmith cp, instance->gpos_gweek, instance->gpos_sweek); 87467754Smsmith return (NULL); 87567754Smsmith} 87667754Smsmith 87767754Smsmith/* 87869450Smsmith * jupiter_debug - print debug messages 87967754Smsmith */ 88067754Smsmith#if defined(__STDC__) || defined(SYS_WINNT) 88167754Smsmithstatic void 88267754Smsmithjupiter_debug(struct peer *peer, char *function, char *fmt, ...) 88367754Smsmith#else 88467754Smsmithstatic void 88567754Smsmithjupiter_debug(peer, function, fmt, va_alist) 88667754Smsmith struct peer *peer; 88767754Smsmith char *function; 88867754Smsmith char *fmt; 88967754Smsmith#endif /* __STDC__ */ 89067754Smsmith{ 89167754Smsmith char buffer[200]; 89267754Smsmith va_list ap; 89367754Smsmith 89467754Smsmith#if defined(__STDC__) || defined(SYS_WINNT) 89567754Smsmith va_start(ap, fmt); 89667754Smsmith#else 89767754Smsmith va_start(ap); 89891116Smsmith#endif /* __STDC__ */ 89991116Smsmith /* 90091116Smsmith * Print debug message to stdout 90191116Smsmith * In the future, we may want to get get more creative... 90267754Smsmith */ 90367754Smsmith vsnprintf(buffer, sizeof(buffer), fmt, ap); 90467754Smsmith record_clock_stats(&(peer->srcadr), buffer); 90567754Smsmith#ifdef DEBUG 90667754Smsmith if (debug) { 90767754Smsmith fprintf(stdout, "%s: ", function); 90867754Smsmith fprintf(stdout, buffer); 90967754Smsmith fprintf(stdout, "\n"); 91091116Smsmith fflush(stdout); 91191116Smsmith } 91267754Smsmith#endif 91367754Smsmith 91467754Smsmith va_end(ap); 91567754Smsmith} 91667754Smsmith 91767754Smsmith/* Checksum and transmit a message to the Jupiter */ 91867754Smsmithstatic char * 91967754Smsmithjupiter_send(struct instance *instance, struct jheader *hp) 92067754Smsmith{ 92167754Smsmith u_int len, size; 92267754Smsmith int cc; 92367754Smsmith u_short *sp; 92467754Smsmith static char errstr[132]; 92567754Smsmith 92667754Smsmith size = sizeof(*hp); 92767754Smsmith hp->hsum = putshort(jupiter_cksum((u_short *)hp, 92867754Smsmith (size / sizeof(u_short)) - 1)); 92967754Smsmith len = getshort(hp->len); 93067754Smsmith if (len > 0) { 93167754Smsmith sp = (u_short *)(hp + 1); 93267754Smsmith sp[len] = putshort(jupiter_cksum(sp, len)); 93367754Smsmith size += (len + 1) * sizeof(u_short); 93467754Smsmith } 93567754Smsmith 93667754Smsmith if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { 93767754Smsmith (void)sprintf(errstr, "write: %s", strerror(errno)); 93867754Smsmith return (errstr); 93967754Smsmith } else if (cc != size) { 94067754Smsmith (void)sprintf(errstr, "short write (%d != %d)", cc, size); 94167754Smsmith return (errstr); 94267754Smsmith } 94367754Smsmith return (NULL); 94467754Smsmith} 94567754Smsmith 94667754Smsmith/* Request periodic message output */ 94767754Smsmithstatic struct { 94867754Smsmith struct jheader jheader; 94967754Smsmith struct jrequest jrequest; 95067754Smsmith} reqmsg = { 95167754Smsmith { putshort(JUPITER_SYNC), 0, 95267754Smsmith putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 953 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 954 JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 }, 955 { 0, 0, 0, 0 } 956}; 957 958/* An interval of zero means to output on trigger */ 959static void 960jupiter_reqmsg(struct instance *instance, u_int id, 961 u_int interval) 962{ 963 struct jheader *hp; 964 struct jrequest *rp; 965 char *cp; 966 967 hp = &reqmsg.jheader; 968 hp->id = putshort(id); 969 rp = &reqmsg.jrequest; 970 rp->trigger = putshort(interval == 0); 971 rp->interval = putshort(interval); 972 if ((cp = jupiter_send(instance, hp)) != NULL) 973 jupiter_debug(instance->peer, "jupiter_reqmsg", "%u: %s", id, cp); 974} 975 976/* Cancel periodic message output */ 977static struct jheader canmsg = { 978 putshort(JUPITER_SYNC), 0, 0, 0, 979 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC, 980 0 981}; 982 983static void 984jupiter_canmsg(struct instance *instance, u_int id) 985{ 986 struct jheader *hp; 987 char *cp; 988 989 hp = &canmsg; 990 hp->id = putshort(id); 991 if ((cp = jupiter_send(instance, hp)) != NULL) 992 jupiter_debug(instance->peer, "jupiter_canmsg", "%u: %s", id, cp); 993} 994 995/* Request a single message output */ 996static struct jheader reqonemsg = { 997 putshort(JUPITER_SYNC), 0, 0, 0, 998 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY, 999 0 1000}; 1001 1002static void 1003jupiter_reqonemsg(struct instance *instance, u_int id) 1004{ 1005 struct jheader *hp; 1006 char *cp; 1007 1008 hp = &reqonemsg; 1009 hp->id = putshort(id); 1010 if ((cp = jupiter_send(instance, hp)) != NULL) 1011 jupiter_debug(instance->peer, "jupiter_reqonemsg", "%u: %s", id, cp); 1012} 1013 1014/* Set the platform dynamics */ 1015static struct { 1016 struct jheader jheader; 1017 struct jplat jplat; 1018} platmsg = { 1019 { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 1020 putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 1021 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 }, 1022 { 0, 0, 0 } 1023}; 1024 1025static void 1026jupiter_platform(struct instance *instance, u_int platform) 1027{ 1028 struct jheader *hp; 1029 struct jplat *pp; 1030 char *cp; 1031 1032 hp = &platmsg.jheader; 1033 pp = &platmsg.jplat; 1034 pp->platform = putshort(platform); 1035 if ((cp = jupiter_send(instance, hp)) != NULL) 1036 jupiter_debug(instance->peer, "jupiter_platform", "%u: %s", platform, cp); 1037} 1038 1039/* Checksum "len" shorts */ 1040static u_short 1041jupiter_cksum(u_short *sp, u_int len) 1042{ 1043 u_short sum, x; 1044 1045 sum = 0; 1046 while (len-- > 0) { 1047 x = *sp++; 1048 sum += getshort(x); 1049 } 1050 return (~sum + 1); 1051} 1052 1053/* Return the size of the next message (or zero if we don't have it all yet) */ 1054static int 1055jupiter_recv(struct instance *instance) 1056{ 1057 int n, len, size, cc; 1058 struct jheader *hp; 1059 u_char *bp; 1060 u_short *sp; 1061 1062 /* Must have at least a header's worth */ 1063 cc = sizeof(*hp); 1064 size = instance->ssize; 1065 if (size < cc) 1066 return (0); 1067 1068 /* Search for the sync short if missing */ 1069 sp = instance->sbuf; 1070 hp = (struct jheader *)sp; 1071 if (getshort(hp->sync) != JUPITER_SYNC) { 1072 /* Wasn't at the front, sync up */ 1073 jupiter_debug(instance->peer, "jupiter_recv", "syncing"); 1074 bp = (u_char *)sp; 1075 n = size; 1076 while (n >= 2) { 1077 if (bp[0] != (JUPITER_SYNC & 0xff)) { 1078 /* 1079 jupiter_debug(instance->peer, "{0x%x}", bp[0]); 1080 */ 1081 ++bp; 1082 --n; 1083 continue; 1084 } 1085 if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 1086 break; 1087 /* 1088 jupiter_debug(instance->peer, "{0x%x 0x%x}", bp[0], bp[1]); 1089 */ 1090 bp += 2; 1091 n -= 2; 1092 } 1093 /* 1094 jupiter_debug(instance->peer, "\n"); 1095 */ 1096 /* Shuffle data to front of input buffer */ 1097 if (n > 0) 1098 memcpy(sp, bp, n); 1099 size = n; 1100 instance->ssize = size; 1101 if (size < cc || hp->sync != JUPITER_SYNC) 1102 return (0); 1103 } 1104 1105 if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1106 getshort(hp->hsum)) { 1107 jupiter_debug(instance->peer, "jupiter_recv", "bad header checksum!"); 1108 /* This is drastic but checksum errors should be rare */ 1109 instance->ssize = 0; 1110 return (0); 1111 } 1112 1113 /* Check for a payload */ 1114 len = getshort(hp->len); 1115 if (len > 0) { 1116 n = (len + 1) * sizeof(u_short); 1117 /* Not enough data yet */ 1118 if (size < cc + n) 1119 return (0); 1120 1121 /* Check payload checksum */ 1122 sp = (u_short *)(hp + 1); 1123 if (jupiter_cksum(sp, len) != getshort(sp[len])) { 1124 jupiter_debug(instance->peer, 1125 "jupiter_recv", "bad payload checksum!"); 1126 /* This is drastic but checksum errors should be rare */ 1127 instance->ssize = 0; 1128 return (0); 1129 } 1130 cc += n; 1131 } 1132 return (cc); 1133} 1134 1135#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1136int refclock_jupiter_bs; 1137#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1138