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