154359Sroberto/*
2132451Sroberto * Copyright (c) 1997, 1998, 2003
354359Sroberto *	The Regents of the University of California.  All rights reserved.
454359Sroberto *
554359Sroberto * Redistribution and use in source and binary forms, with or without
654359Sroberto * modification, are permitted provided that the following conditions
754359Sroberto * are met:
854359Sroberto * 1. Redistributions of source code must retain the above copyright
954359Sroberto *    notice, this list of conditions and the following disclaimer.
1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1154359Sroberto *    notice, this list of conditions and the following disclaimer in the
1254359Sroberto *    documentation and/or other materials provided with the distribution.
1354359Sroberto * 3. All advertising materials mentioning features or use of this software
1454359Sroberto *    must display the following acknowledgement:
1554359Sroberto *	This product includes software developed by the University of
1654359Sroberto *	California, Lawrence Berkeley Laboratory.
1754359Sroberto * 4. The name of the University may not be used to endorse or promote
1854359Sroberto *    products derived from this software without specific prior
1954359Sroberto *    written permission.
2054359Sroberto *
2154359Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2254359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2354359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2454359Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2554359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2654359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2754359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2854359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2954359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3054359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3154359Sroberto * SUCH DAMAGE.
3254359Sroberto */
3354359Sroberto
3454359Sroberto#ifdef HAVE_CONFIG_H
3554359Sroberto# include <config.h>
3654359Sroberto#endif
3754359Sroberto
38358659Scy/* This clock *REQUIRES* the PPS API to be available */
39132451Sroberto#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI)
4054359Sroberto
4154359Sroberto#include "ntpd.h"
4254359Sroberto#include "ntp_io.h"
4354359Sroberto#include "ntp_refclock.h"
4454359Sroberto#include "ntp_unixtime.h"
4554359Sroberto#include "ntp_stdlib.h"
46358659Scy#include "ntp_calendar.h"
47358659Scy#include "ntp_calgps.h"
48358659Scy#include "timespecops.h"
4954359Sroberto
5082498Sroberto#include <stdio.h>
5182498Sroberto#include <ctype.h>
5282498Sroberto
5354359Sroberto#include "jupiter.h"
54358659Scy#include "ppsapi_timepps.h"
5554359Sroberto
56280849Scy#ifdef WORDS_BIGENDIAN
5754359Sroberto#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
5854359Sroberto#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
5954359Sroberto#else
60280849Scy#define getshort(s) ((u_short)(s))
61280849Scy#define putshort(s) ((u_short)(s))
6254359Sroberto#endif
6354359Sroberto
6454359Sroberto/*
6554359Sroberto * This driver supports the Rockwell Jupiter GPS Receiver board
6654359Sroberto * adapted to precision timing applications.  It requires the
6754359Sroberto * ppsclock line discipline or streams module described in the
6854359Sroberto * Line Disciplines and Streams Drivers page. It also requires a
6954359Sroberto * gadget box and 1-PPS level converter, such as described in the
7054359Sroberto * Pulse-per-second (PPS) Signal Interfacing page.
7154359Sroberto *
7254359Sroberto * It may work (with minor modifications) with other Rockwell GPS
7354359Sroberto * receivers such as the CityTracker.
7454359Sroberto */
7554359Sroberto
7654359Sroberto/*
7754359Sroberto * GPS Definitions
7854359Sroberto */
7954359Sroberto#define	DEVICE		"/dev/gps%d"	/* device name and unit */
8054359Sroberto#define	SPEED232	B9600		/* baud */
8154359Sroberto
8254359Sroberto/*
8354359Sroberto * Radio interface parameters
8454359Sroberto */
8554359Sroberto#define	PRECISION	(-18)	/* precision assumed (about 4 us) */
8654359Sroberto#define	REFID	"GPS\0"		/* reference id */
8754359Sroberto#define	DESCRIPTION	"Rockwell Jupiter GPS Receiver" /* who we are */
8854359Sroberto#define	DEFFUDGETIME	0	/* default fudge time (ms) */
8954359Sroberto
9054359Sroberto/* Unix timestamp for the GPS epoch: January 6, 1980 */
9154359Sroberto#define GPS_EPOCH 315964800
9254359Sroberto
93309007Sdelphij/* Rata Die Number of first day of GPS epoch. This is the number of days
94309007Sdelphij * since 0000-12-31 to 1980-01-06 in the proleptic Gregorian Calendar.
95309007Sdelphij */
96309007Sdelphij#define RDN_GPS_EPOCH (4*146097 + 138431 + 1)
97309007Sdelphij
9854359Sroberto/* Double short to unsigned int */
9954359Sroberto#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
10054359Sroberto
10154359Sroberto/* Double short to signed int */
10254359Sroberto#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
10354359Sroberto
10454359Sroberto/* One week's worth of seconds */
10554359Sroberto#define WEEKSECS (7 * 24 * 60 * 60)
10654359Sroberto
10754359Sroberto/*
10854359Sroberto * Jupiter unit control structure.
10954359Sroberto */
110132451Srobertostruct instance {
111132451Sroberto	struct peer *peer;		/* peer */
112358659Scy
113132451Sroberto	pps_params_t pps_params;	/* pps parameters */
114132451Sroberto	pps_info_t pps_info;		/* last pps data */
115132451Sroberto	pps_handle_t pps_handle;	/* pps handle */
116358659Scy	u_int	assert;			/* pps edge to use */
117358659Scy	u_int	hardpps;		/* enable kernel mode */
118358659Scy	l_fp 		rcv_pps;	/* last pps timestamp */
119358659Scy	l_fp	        rcv_next;	/* rcv time of next reftime */
120358659Scy	TGpsDatum	ref_next;	/* next GPS time stamp to use with PPS */
121358659Scy	TGpsDatum	piv_next;	/* pivot for week date unfolding */
122358659Scy	uint16_t	piv_hold;	/* TTL for pivot value */
123358659Scy	uint16_t	rcvtout;	/* receive timeout ticker */
12454359Sroberto	int wantid;			/* don't reconfig on channel id msg */
12554359Sroberto	u_int  moving;			/* mobile platform? */
126132451Sroberto	u_char sloppyclockflag;		/* fudge flags */
12754359Sroberto	u_short sbuf[512];		/* local input buffer */
12854359Sroberto	int ssize;			/* space used in sbuf */
12954359Sroberto};
13054359Sroberto
13154359Sroberto/*
13254359Sroberto * Function prototypes
13354359Sroberto */
134358659Scystatic	void	jupiter_canmsg	(struct instance * const, u_int);
135280849Scystatic	u_short	jupiter_cksum	(u_short *, u_int);
136358659Scystatic	int	jupiter_config	(struct instance * const);
137280849Scystatic	void	jupiter_debug	(struct peer *, const char *,
138338530Sdelphij				 const char *, ...) NTP_PRINTF(3, 4);
139358659Scystatic	const char *	jupiter_parse_t	(struct instance * const, u_short *, l_fp);
140358659Scystatic	const char *	jupiter_parse_gpos(struct instance * const, u_short *);
141358659Scystatic	void	jupiter_platform(struct instance * const, u_int);
142280849Scystatic	void	jupiter_poll	(int, struct peer *);
143280849Scystatic	void	jupiter_control	(int, const struct refclockstat *,
144280849Scy				 struct refclockstat *, struct peer *);
145358659Scystatic	int	jupiter_ppsapi	(struct instance * const);
146358659Scystatic	int	jupiter_pps	(struct instance * const);
147358659Scystatic	int	jupiter_recv	(struct instance * const);
148358659Scystatic	void	jupiter_receive (struct recvbuf * const rbufp);
149358659Scystatic	void	jupiter_reqmsg	(struct instance * const, u_int, u_int);
150358659Scystatic	void	jupiter_reqonemsg(struct instance * const, u_int);
151358659Scystatic	char *	jupiter_send	(struct instance * const, struct jheader *);
152280849Scystatic	void	jupiter_shutdown(int, struct peer *);
153280849Scystatic	int	jupiter_start	(int, struct peer *);
154358659Scystatic	void	jupiter_ticker	(int, struct peer *);
15554359Sroberto
15654359Sroberto/*
15754359Sroberto * Transfer vector
15854359Sroberto */
15954359Srobertostruct	refclock refclock_jupiter = {
16054359Sroberto	jupiter_start,		/* start up driver */
16154359Sroberto	jupiter_shutdown,	/* shut down driver */
16254359Sroberto	jupiter_poll,		/* transmit poll message */
163132451Sroberto	jupiter_control,	/* (clock control) */
16454359Sroberto	noentry,		/* (clock init) */
16554359Sroberto	noentry,		/* (clock buginfo) */
166358659Scy	jupiter_ticker		/* 1HZ ticker */
16754359Sroberto};
16854359Sroberto
16954359Sroberto/*
17054359Sroberto * jupiter_start - open the devices and initialize data for processing
17154359Sroberto */
17254359Srobertostatic int
17354359Srobertojupiter_start(
174132451Sroberto	int unit,
175132451Sroberto	struct peer *peer
17654359Sroberto	)
17754359Sroberto{
178358659Scy	struct refclockproc * const pp = peer->procptr;
179358659Scy	struct instance * up;
180280849Scy	int fd;
18154359Sroberto	char gpsdev[20];
18254359Sroberto
18354359Sroberto	/*
18454359Sroberto	 * Open serial port
18554359Sroberto	 */
186280849Scy	snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
187132451Sroberto	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
188280849Scy	if (fd <= 0) {
189280849Scy		jupiter_debug(peer, "jupiter_start", "open %s: %m",
190280849Scy			      gpsdev);
19154359Sroberto		return (0);
19254359Sroberto	}
19354359Sroberto
19454359Sroberto	/* Allocate unit structure */
195358659Scy	up = emalloc_zero(sizeof(*up));
196358659Scy	up->peer = peer;
19754359Sroberto	pp->io.clock_recv = jupiter_receive;
198280849Scy	pp->io.srcclock = peer;
19954359Sroberto	pp->io.datalen = 0;
20054359Sroberto	pp->io.fd = fd;
20154359Sroberto	if (!io_addclock(&pp->io)) {
202280849Scy		close(fd);
203280849Scy		pp->io.fd = -1;
204358659Scy		free(up);
20554359Sroberto		return (0);
20654359Sroberto	}
207358659Scy	pp->unitptr = up;
20854359Sroberto
20954359Sroberto	/*
21054359Sroberto	 * Initialize miscellaneous variables
21154359Sroberto	 */
21254359Sroberto	peer->precision = PRECISION;
21354359Sroberto	pp->clockdesc = DESCRIPTION;
21454359Sroberto	memcpy((char *)&pp->refid, REFID, 4);
21554359Sroberto
216358659Scy	up->assert = 1;
217358659Scy	up->hardpps = 0;
218132451Sroberto	/*
219132451Sroberto	 * Start the PPSAPI interface if it is there. Default to use
220132451Sroberto	 * the assert edge and do not enable the kernel hardpps.
221132451Sroberto	 */
222358659Scy	if (time_pps_create(fd, &up->pps_handle) < 0) {
223358659Scy		up->pps_handle = 0;
224132451Sroberto		msyslog(LOG_ERR,
225132451Sroberto			"refclock_jupiter: time_pps_create failed: %m");
226132451Sroberto	}
227358659Scy	else if (!jupiter_ppsapi(up))
228132451Sroberto		goto clean_up;
229358659Scy
23054359Sroberto	/* Ensure the receiver is properly configured */
231358659Scy	if (!jupiter_config(up))
232132451Sroberto		goto clean_up;
23354359Sroberto
234358659Scy	jupiter_pps(up);	/* get current PPS state */
23554359Sroberto	return (1);
236132451Sroberto
237132451Srobertoclean_up:
238132451Sroberto	jupiter_shutdown(unit, peer);
239132451Sroberto	pp->unitptr = 0;
240132451Sroberto	return (0);
24154359Sroberto}
24254359Sroberto
24354359Sroberto/*
24454359Sroberto * jupiter_shutdown - shut down the clock
24554359Sroberto */
24654359Srobertostatic void
247132451Srobertojupiter_shutdown(int unit, struct peer *peer)
24854359Sroberto{
249358659Scy	struct refclockproc * const pp = peer->procptr;
250358659Scy	struct instance *     const up = pp->unitptr;
251358659Scy
252358659Scy	if (!up)
253132451Sroberto		return;
254132451Sroberto
255358659Scy	if (up->pps_handle) {
256358659Scy		time_pps_destroy(up->pps_handle);
257358659Scy		up->pps_handle = 0;
258132451Sroberto	}
259132451Sroberto
260280849Scy	if (pp->io.fd != -1)
261280849Scy		io_closeclock(&pp->io);
262358659Scy	free(up);
26354359Sroberto}
26454359Sroberto
26554359Sroberto/*
26654359Sroberto * jupiter_config - Configure the receiver
26754359Sroberto */
268132451Srobertostatic int
269358659Scyjupiter_config(struct instance * const up)
27054359Sroberto{
271358659Scy	jupiter_debug(up->peer, __func__, "init receiver");
27254359Sroberto
27354359Sroberto	/*
27454359Sroberto	 * Initialize the unit variables
27554359Sroberto	 */
276358659Scy	up->sloppyclockflag = up->peer->procptr->sloppyclockflag;
277358659Scy	up->moving = !!(up->sloppyclockflag & CLK_FLAG2);
278358659Scy	if (up->moving)
279358659Scy		jupiter_debug(up->peer, __func__, "mobile platform");
28054359Sroberto
281358659Scy	ZERO(up->rcv_next);
282358659Scy	ZERO(up->ref_next);
283358659Scy	ZERO(up->piv_next);
284358659Scy	up->ssize = 0;
28554359Sroberto
28654359Sroberto	/* Stop outputting all messages */
287358659Scy	jupiter_canmsg(up, JUPITER_ALL);
28854359Sroberto
28954359Sroberto	/* Request the receiver id so we can syslog the firmware version */
290358659Scy	jupiter_reqonemsg(up, JUPITER_O_ID);
29154359Sroberto
29254359Sroberto	/* Flag that this the id was requested (so we don't get called again) */
293358659Scy	up->wantid = 1;
29454359Sroberto
29554359Sroberto	/* Request perodic time mark pulse messages */
296358659Scy	jupiter_reqmsg(up, JUPITER_O_PULSE, 1);
29754359Sroberto
298132451Sroberto	/* Request perodic geodetic position status */
299358659Scy	jupiter_reqmsg(up, JUPITER_O_GPOS, 1);
300132451Sroberto
30154359Sroberto	/* Set application platform type */
302358659Scy	if (up->moving)
303358659Scy		jupiter_platform(up, JUPITER_I_PLAT_MED);
30454359Sroberto	else
305358659Scy		jupiter_platform(up, JUPITER_I_PLAT_LOW);
306132451Sroberto
307132451Sroberto	return (1);
30854359Sroberto}
30954359Sroberto
310358659Scystatic void
311358659Scyjupiter_checkpps(
312358659Scy	struct refclockproc * const pp,
313358659Scy	struct instance *     const up
314358659Scy	)
315358659Scy{
316358659Scy	l_fp		tstamp, delta;
317358659Scy	struct calendar	cd;
318358659Scy
319358659Scy	if (jupiter_pps(up) || !up->piv_next.weeks)
320358659Scy		return;
321358659Scy
322358659Scy	/* check delay between pulse message and pulse. */
323358659Scy	delta = up->rcv_pps;		/* set by jupiter_pps() */
324358659Scy	L_SUB(&delta, &up->rcv_next);	/* recv time pulse message */
325358659Scy	if (delta.l_ui != 0 || delta.l_uf >= 0xC0000000) {
326358659Scy		up->ref_next.weeks = 0;	/* consider as consumed... */
327358659Scy		return;
328358659Scy	}
329358659Scy
330358659Scy	pp->lastrec = up->rcv_pps;
331358659Scy	tstamp = ntpfp_from_gpsdatum(&up->ref_next);
332358659Scy	refclock_process_offset(pp, tstamp, up->rcv_pps, pp->fudgetime1);
333358659Scy	up->rcvtout = 2;
334358659Scy
335358659Scy	gpscal_to_calendar(&cd, &up->ref_next);
336358659Scy	refclock_save_lcode(pp, ntpcal_iso8601std(NULL, 0, &cd),
337358659Scy			    (size_t)-1);
338358659Scy	up->ref_next.weeks = 0;	/* consumed... */
339358659Scy}
340358659Scy
34154359Sroberto/*
342358659Scy * jupiter_ticker - process periodic checks
343358659Scy */
344358659Scystatic void
345358659Scyjupiter_ticker(int unit, struct peer *peer)
346358659Scy{
347358659Scy	struct refclockproc * const pp = peer->procptr;
348358659Scy	struct instance *     const up = pp->unitptr;
349358659Scy
350358659Scy	if (!up)
351358659Scy		return;
352358659Scy
353358659Scy	/* check if we can add another sample now */
354358659Scy	jupiter_checkpps(pp, up);
355358659Scy
356358659Scy	/* check the pivot update cycle */
357358659Scy	if (up->piv_hold && !--up->piv_hold)
358358659Scy		ZERO(up->piv_next);
359358659Scy
360358659Scy	if (up->rcvtout)
361358659Scy		--up->rcvtout;
362358659Scy	else if (pp->coderecv != pp->codeproc)
363358659Scy		refclock_samples_expire(pp, 1);
364358659Scy}
365358659Scy
366358659Scy/*
367132451Sroberto * Initialize PPSAPI
368132451Sroberto */
369132451Srobertoint
370132451Srobertojupiter_ppsapi(
371358659Scy	struct instance * const up	/* unit structure pointer */
372132451Sroberto	)
373132451Sroberto{
374132451Sroberto	int capability;
375132451Sroberto
376358659Scy	if (time_pps_getcap(up->pps_handle, &capability) < 0) {
377132451Sroberto		msyslog(LOG_ERR,
378132451Sroberto		    "refclock_jupiter: time_pps_getcap failed: %m");
379132451Sroberto		return (0);
380132451Sroberto	}
381358659Scy	memset(&up->pps_params, 0, sizeof(pps_params_t));
382358659Scy	if (!up->assert)
383358659Scy		up->pps_params.mode = capability & PPS_CAPTURECLEAR;
384132451Sroberto	else
385358659Scy		up->pps_params.mode = capability & PPS_CAPTUREASSERT;
386358659Scy	if (!(up->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
387132451Sroberto		msyslog(LOG_ERR,
388132451Sroberto		    "refclock_jupiter: invalid capture edge %d",
389358659Scy		    up->assert);
390132451Sroberto		return (0);
391132451Sroberto	}
392358659Scy	up->pps_params.mode |= PPS_TSFMT_TSPEC;
393358659Scy	if (time_pps_setparams(up->pps_handle, &up->pps_params) < 0) {
394132451Sroberto		msyslog(LOG_ERR,
395132451Sroberto		    "refclock_jupiter: time_pps_setparams failed: %m");
396132451Sroberto		return (0);
397132451Sroberto	}
398358659Scy	if (up->hardpps) {
399358659Scy		if (time_pps_kcbind(up->pps_handle, PPS_KC_HARDPPS,
400358659Scy				    up->pps_params.mode & ~PPS_TSFMT_TSPEC,
401132451Sroberto				    PPS_TSFMT_TSPEC) < 0) {
402132451Sroberto			msyslog(LOG_ERR,
403132451Sroberto			    "refclock_jupiter: time_pps_kcbind failed: %m");
404132451Sroberto			return (0);
405132451Sroberto		}
406280849Scy		hardpps_enable = 1;
407132451Sroberto	}
408358659Scy/*	up->peer->precision = PPS_PRECISION; */
409132451Sroberto
410132451Sroberto#if DEBUG
411132451Sroberto	if (debug) {
412358659Scy		time_pps_getparams(up->pps_handle, &up->pps_params);
413358659Scy		jupiter_debug(up->peer, __func__,
414132451Sroberto			"pps capability 0x%x version %d mode 0x%x kern %d",
415358659Scy			capability, up->pps_params.api_version,
416358659Scy			up->pps_params.mode, up->hardpps);
417132451Sroberto	}
418132451Sroberto#endif
419132451Sroberto
420132451Sroberto	return (1);
421132451Sroberto}
422132451Sroberto
423132451Sroberto/*
424132451Sroberto * Get PPSAPI timestamps.
425132451Sroberto *
426132451Sroberto * Return 0 on failure and 1 on success.
427132451Sroberto */
428132451Srobertostatic int
429358659Scyjupiter_pps(struct instance * const up)
430132451Sroberto{
431132451Sroberto	pps_info_t pps_info;
432132451Sroberto	struct timespec timeout, ts;
433132451Sroberto	l_fp tstmp;
434132451Sroberto
435132451Sroberto	/*
436132451Sroberto	 * Convert the timespec nanoseconds field to ntp l_fp units.
437132451Sroberto	 */
438358659Scy	if (up->pps_handle == 0)
439132451Sroberto		return 1;
440132451Sroberto	timeout.tv_sec = 0;
441132451Sroberto	timeout.tv_nsec = 0;
442358659Scy	memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
443358659Scy	if (time_pps_fetch(up->pps_handle, PPS_TSFMT_TSPEC, &up->pps_info,
444132451Sroberto	    &timeout) < 0)
445132451Sroberto		return 1;
446358659Scy	if (up->pps_params.mode & PPS_CAPTUREASSERT) {
447132451Sroberto		if (pps_info.assert_sequence ==
448358659Scy		    up->pps_info.assert_sequence)
449132451Sroberto			return 1;
450358659Scy		ts = up->pps_info.assert_timestamp;
451358659Scy	} else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
452132451Sroberto		if (pps_info.clear_sequence ==
453358659Scy		    up->pps_info.clear_sequence)
454132451Sroberto			return 1;
455358659Scy		ts = up->pps_info.clear_timestamp;
456132451Sroberto	} else {
457132451Sroberto		return 1;
458132451Sroberto	}
459358659Scy
460358659Scy	tstmp = tspec_stamp_to_lfp(ts);
461358659Scy	if (L_ISEQU(&tstmp, &up->rcv_pps))
462132451Sroberto		return 1;
463132451Sroberto
464358659Scy	up->rcv_pps = tstmp;
465132451Sroberto	return 0;
466132451Sroberto}
467132451Sroberto
468132451Sroberto/*
46954359Sroberto * jupiter_poll - jupiter watchdog routine
47054359Sroberto */
47154359Srobertostatic void
472132451Srobertojupiter_poll(int unit, struct peer *peer)
47354359Sroberto{
474358659Scy	struct refclockproc * const pp = peer->procptr;
475358659Scy	struct instance *     const up = pp->unitptr;
47654359Sroberto
477358659Scy	pp->polls++;
47854359Sroberto
47954359Sroberto	/*
480358659Scy	 * If we have new samples since last poll, everything is fine.
481358659Scy	 * if not, blarb loudly.
48254359Sroberto	 */
483358659Scy	if (pp->coderecv != pp->codeproc) {
484358659Scy		refclock_receive(peer);
485358659Scy		refclock_report(peer, CEVNT_NOMINAL);
48654359Sroberto	} else {
48754359Sroberto		refclock_report(peer, CEVNT_TIMEOUT);
48854359Sroberto
48954359Sroberto		/* Request the receiver id to trigger a reconfig */
490358659Scy		jupiter_reqonemsg(up, JUPITER_O_ID);
491358659Scy		up->wantid = 0;
49254359Sroberto	}
49354359Sroberto}
49454359Sroberto
49554359Sroberto/*
496132451Sroberto * jupiter_control - fudge control
49754359Sroberto */
49854359Srobertostatic void
499132451Srobertojupiter_control(
500132451Sroberto	int unit,		/* unit (not used) */
501280849Scy	const struct refclockstat *in, /* input parameters (not used) */
502132451Sroberto	struct refclockstat *out, /* output parameters (not used) */
503132451Sroberto	struct peer *peer	/* peer structure pointer */
504132451Sroberto	)
50554359Sroberto{
506358659Scy	struct refclockproc * const pp = peer->procptr;
507358659Scy	struct instance *     const up = pp->unitptr;
508358659Scy
509132451Sroberto	u_char sloppyclockflag;
51054359Sroberto
511358659Scy	up->assert = !(pp->sloppyclockflag & CLK_FLAG3);
512358659Scy	jupiter_ppsapi(up);
51354359Sroberto
514358659Scy	sloppyclockflag = up->sloppyclockflag;
515358659Scy	up->sloppyclockflag = pp->sloppyclockflag;
516358659Scy	if ((up->sloppyclockflag & CLK_FLAG2) !=
51754359Sroberto	    (sloppyclockflag & CLK_FLAG2)) {
518280849Scy		jupiter_debug(peer, __func__,
519132451Sroberto		    "mode switch: reset receiver");
520358659Scy		jupiter_config(up);
52154359Sroberto		return;
52254359Sroberto	}
523132451Sroberto}
52454359Sroberto
525132451Sroberto/*
526132451Sroberto * jupiter_receive - receive gps data
527132451Sroberto * Gag me!
528132451Sroberto */
529132451Srobertostatic void
530358659Scyjupiter_receive(struct recvbuf * const rbufp)
531132451Sroberto{
532358659Scy	struct peer *         const peer = rbufp->recv_peer;
533358659Scy	struct refclockproc * const pp   = peer->procptr;
534358659Scy	struct instance *     const up   = pp->unitptr;
535358659Scy
536280849Scy	size_t bpcnt;
537358659Scy	int cc, size;
538280849Scy	const char *cp;
539132451Sroberto	u_char *bp;
540132451Sroberto	u_short *sp;
541132451Sroberto	struct jid *ip;
542132451Sroberto	struct jheader *hp;
54354359Sroberto
544132451Sroberto	/* Initialize pointers and read the timecode and timestamp */
54554359Sroberto	bp = (u_char *)rbufp->recv_buffer;
54654359Sroberto	bpcnt = rbufp->recv_length;
54754359Sroberto
54854359Sroberto	/* This shouldn't happen */
549358659Scy	if (bpcnt > sizeof(up->sbuf) - up->ssize)
550358659Scy		bpcnt = sizeof(up->sbuf) - up->ssize;
55154359Sroberto
55254359Sroberto	/* Append to input buffer */
553358659Scy	memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt);
554358659Scy	up->ssize += bpcnt;
55554359Sroberto
556132451Sroberto	/* While there's at least a header and we parse an intact message */
557358659Scy	while (up->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(up)) > 0) {
558358659Scy		hp = (struct jheader *)up->sbuf;
55954359Sroberto		sp = (u_short *)(hp + 1);
56054359Sroberto		size = cc - sizeof(*hp);
56154359Sroberto		switch (getshort(hp->id)) {
56254359Sroberto
56354359Sroberto		case JUPITER_O_PULSE:
564358659Scy			/* first see if we can push another sample: */
565358659Scy			jupiter_checkpps(pp, up);
566358659Scy
56754359Sroberto			if (size != sizeof(struct jpulse)) {
568280849Scy				jupiter_debug(peer, __func__,
569280849Scy				    "pulse: len %d != %u",
57054359Sroberto				    size, (int)sizeof(struct jpulse));
57154359Sroberto				refclock_report(peer, CEVNT_BADREPLY);
57254359Sroberto				break;
57354359Sroberto			}
574358659Scy
575358659Scy			/* Parse timecode (even when there's no pps)
576358659Scy			 *
577358659Scy			 * There appears to be a firmware bug related to
578358659Scy			 * the pulse message; in addition to the one per
579358659Scy			 * second messages, we get an extra pulse
58054359Sroberto			 * message once an hour (on the anniversary of
58154359Sroberto			 * the cold start). It seems to come 200 ms
582358659Scy			 * after the one requested.
583358659Scy			 *
584358659Scy			 * But since we feed samples only when a new PPS
585358659Scy			 * pulse is found we can simply ignore that and
586358659Scy			 * aggregate/update any existing timing message.
58754359Sroberto			 */
588358659Scy			if ((cp = jupiter_parse_t(up, sp, rbufp->recv_time)) != NULL) {
589280849Scy				jupiter_debug(peer, __func__,
590280849Scy				    "pulse: %s", cp);
59154359Sroberto			}
59254359Sroberto			break;
59354359Sroberto
594132451Sroberto		case JUPITER_O_GPOS:
595132451Sroberto			if (size != sizeof(struct jgpos)) {
596280849Scy				jupiter_debug(peer, __func__,
597280849Scy				    "gpos: len %d != %u",
598132451Sroberto				    size, (int)sizeof(struct jgpos));
599132451Sroberto				refclock_report(peer, CEVNT_BADREPLY);
600132451Sroberto				break;
601132451Sroberto			}
602132451Sroberto
603358659Scy			if ((cp = jupiter_parse_gpos(up, sp)) != NULL) {
604280849Scy				jupiter_debug(peer, __func__,
605280849Scy				    "gpos: %s", cp);
606132451Sroberto				break;
607132451Sroberto			}
608132451Sroberto			break;
609132451Sroberto
61054359Sroberto		case JUPITER_O_ID:
61154359Sroberto			if (size != sizeof(struct jid)) {
612280849Scy				jupiter_debug(peer, __func__,
613280849Scy				    "id: len %d != %u",
61454359Sroberto				    size, (int)sizeof(struct jid));
61554359Sroberto				refclock_report(peer, CEVNT_BADREPLY);
61654359Sroberto				break;
61754359Sroberto			}
61854359Sroberto			/*
61954359Sroberto			 * If we got this message because the Jupiter
620132451Sroberto			 * just powered instance, it needs to be reconfigured.
62154359Sroberto			 */
62254359Sroberto			ip = (struct jid *)sp;
623280849Scy			jupiter_debug(peer, __func__,
624280849Scy			    "%s chan ver %s, %s (%s)",
62554359Sroberto			    ip->chans, ip->vers, ip->date, ip->opts);
62654359Sroberto			msyslog(LOG_DEBUG,
627182007Sroberto			    "jupiter_receive: %s chan ver %s, %s (%s)",
62854359Sroberto			    ip->chans, ip->vers, ip->date, ip->opts);
629358659Scy			if (up->wantid)
630358659Scy				up->wantid = 0;
63154359Sroberto			else {
632280849Scy				jupiter_debug(peer, __func__, "reset receiver");
633358659Scy				jupiter_config(up);
634132451Sroberto				/*
635132451Sroberto				 * Restore since jupiter_config() just
636132451Sroberto				 * zeroed it
637132451Sroberto				 */
638358659Scy				up->ssize = cc;
63954359Sroberto			}
64054359Sroberto			break;
64154359Sroberto
64254359Sroberto		default:
643280849Scy			jupiter_debug(peer, __func__, "unknown message id %d",
64454359Sroberto			    getshort(hp->id));
64554359Sroberto			break;
64654359Sroberto		}
647358659Scy		up->ssize -= cc;
648358659Scy		if (up->ssize < 0) {
64954359Sroberto			fprintf(stderr, "jupiter_recv: negative ssize!\n");
65054359Sroberto			abort();
651358659Scy		} else if (up->ssize > 0)
652358659Scy			memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize);
65354359Sroberto	}
65454359Sroberto}
65554359Sroberto
656280849Scystatic const char *
657358659Scyjupiter_parse_t(
658358659Scy	struct instance * const up,
659358659Scy	u_short *               sp,
660358659Scy	l_fp               rcvtime
661358659Scy	)
66254359Sroberto{
663132451Sroberto	struct jpulse *jp;
664132451Sroberto	u_int32 sweek;
665132451Sroberto	u_short flags;
666358659Scy	l_fp fofs;
667358659Scy
66854359Sroberto	jp = (struct jpulse *)sp;
669358659Scy	flags = getshort(jp->flags);
67054359Sroberto
671358659Scy	/* Toss if not designated "valid" by the gps.
672358659Scy	 * !!NOTE!! do *not* kill data received so far!
673358659Scy	 */
674358659Scy	if ((flags & JUPITER_O_PULSE_VALID) == 0) {
675358659Scy		refclock_report(up->peer, CEVNT_BADTIME);
676358659Scy		return ("time mark not valid");
677358659Scy	}
678358659Scy
679358659Scy	up->rcv_next = rcvtime; /* remember when this happened */
680358659Scy
68154359Sroberto	/* The timecode is presented as seconds into the current GPS week */
682132451Sroberto	sweek = DS2UI(jp->sweek) % WEEKSECS;
683358659Scy	/* check if we have to apply the UTC offset ourselves */
684358659Scy	if ((flags & JUPITER_O_PULSE_UTC) == 0) {
685358659Scy		struct timespec tofs;
686358659Scy		tofs.tv_sec  = getshort(jp->offs);
687358659Scy		tofs.tv_nsec = DS2I(jp->offns);
688358659Scy		fofs = tspec_intv_to_lfp(tofs);
689358659Scy		L_NEG(&fofs);
690358659Scy	} else {
691358659Scy		ZERO(fofs);
692358659Scy	}
693358659Scy
69454359Sroberto	/*
69554359Sroberto	 * If we don't know the current GPS week, calculate it from the
69654359Sroberto	 * current time. (It's too bad they didn't include this
697358659Scy	 * important value in the pulse message).
698358659Scy	 *
699358659Scy	 * So we pick the pivot value from the other messages like gpos
700358659Scy	 * or chan if we can. Of course, the PULSE message can be in UTC
701358659Scy	 * or GPS time scale, and the other messages are simply always
702358659Scy	 * GPS time.
70354359Sroberto	 *
704358659Scy	 * But as long as the difference between the time stamps is less
705358659Scy	 * than a half week, the unfolding of a week time is unambigeous
706358659Scy	 * and well suited for the problem we have here. And we won't
707358659Scy	 * see *that* many leap seconds, ever.
70854359Sroberto	 */
709358659Scy	if (up->piv_next.weeks) {
710358659Scy		up->ref_next = gpscal_from_weektime2(
711358659Scy			sweek, fofs, &up->piv_next);
712358659Scy		up->piv_next = up->ref_next;
713358659Scy	} else {
714358659Scy		up->ref_next = gpscal_from_weektime1(
715358659Scy			sweek, fofs, rcvtime);
71654359Sroberto	}
717358659Scy
71854359Sroberto
71954359Sroberto
72054359Sroberto	return (NULL);
72154359Sroberto}
72254359Sroberto
723280849Scystatic const char *
724358659Scyjupiter_parse_gpos(
725358659Scy	struct instance * const up,
726358659Scy	u_short *               sp
727358659Scy	)
72854359Sroberto{
729132451Sroberto	struct jgpos *jg;
730358659Scy	struct calendar	tref;
731132451Sroberto	char *cp;
732358659Scy	struct timespec tofs;
733358659Scy	uint16_t	raw_week;
734358659Scy	uint32_t	raw_secs;
73554359Sroberto
736132451Sroberto	jg = (struct jgpos *)sp;
73754359Sroberto
738132451Sroberto	if (jg->navval != 0) {
739132451Sroberto		/*
740132451Sroberto		 * Solution not valid. Use caution and refuse
741132451Sroberto		 * to determine GPS week from this message.
742132451Sroberto		 */
743132451Sroberto		return ("Navigation solution not valid");
74454359Sroberto	}
74554359Sroberto
746358659Scy	raw_week = getshort(jg->gweek);
747358659Scy	raw_secs = DS2UI(jg->sweek);
748358659Scy	tofs.tv_sec  = 0;
749358659Scy	tofs.tv_nsec = DS2UI(jg->nsweek);
750358659Scy	up->piv_next = gpscal_from_gpsweek(raw_week, raw_secs,
751358659Scy					   tspec_intv_to_lfp(tofs));
752358659Scy	up->piv_hold = 60;
753309007Sdelphij
754358659Scy	gpscal_to_calendar(&tref, &up->piv_next);
755358659Scy	cp = ntpcal_iso8601std(NULL, 0, &tref);
756358659Scy	jupiter_debug(up->peer, __func__,
757358659Scy		"GPS %s (gweek/sweek %hu/%u)",
758358659Scy		      cp, (unsigned short)raw_week, (unsigned int)raw_secs);
759132451Sroberto	return (NULL);
76054359Sroberto}
76154359Sroberto
76254359Sroberto/*
76354359Sroberto * jupiter_debug - print debug messages
76454359Sroberto */
76554359Srobertostatic void
766280849Scyjupiter_debug(
767280849Scy	struct peer *	peer,
768280849Scy	const char *	function,
769280849Scy	const char *	fmt,
770280849Scy	...
771280849Scy	)
77254359Sroberto{
773280849Scy	char	buffer[200];
774280849Scy	va_list	ap;
77554359Sroberto
776132451Sroberto	va_start(ap, fmt);
777132451Sroberto	/*
778132451Sroberto	 * Print debug message to stdout
779132451Sroberto	 * In the future, we may want to get get more creative...
780132451Sroberto	 */
781280849Scy	mvsnprintf(buffer, sizeof(buffer), fmt, ap);
782280849Scy	record_clock_stats(&peer->srcadr, buffer);
783182007Sroberto#ifdef DEBUG
784132451Sroberto	if (debug) {
785280849Scy		printf("%s: %s\n", function, buffer);
786132451Sroberto		fflush(stdout);
787132451Sroberto	}
788182007Sroberto#endif
78954359Sroberto
790132451Sroberto	va_end(ap);
79154359Sroberto}
79254359Sroberto
79354359Sroberto/* Checksum and transmit a message to the Jupiter */
79454359Srobertostatic char *
795358659Scyjupiter_send(
796358659Scy	struct instance * const up,
797358659Scy	struct jheader *        hp
798358659Scy	)
79954359Sroberto{
800132451Sroberto	u_int len, size;
801280849Scy	ssize_t cc;
802132451Sroberto	u_short *sp;
80354359Sroberto	static char errstr[132];
80454359Sroberto
80554359Sroberto	size = sizeof(*hp);
80654359Sroberto	hp->hsum = putshort(jupiter_cksum((u_short *)hp,
80754359Sroberto	    (size / sizeof(u_short)) - 1));
80854359Sroberto	len = getshort(hp->len);
80954359Sroberto	if (len > 0) {
81054359Sroberto		sp = (u_short *)(hp + 1);
81154359Sroberto		sp[len] = putshort(jupiter_cksum(sp, len));
81254359Sroberto		size += (len + 1) * sizeof(u_short);
81354359Sroberto	}
81454359Sroberto
815358659Scy	if ((cc = write(up->peer->procptr->io.fd, (char *)hp, size)) < 0) {
816280849Scy		msnprintf(errstr, sizeof(errstr), "write: %m");
81754359Sroberto		return (errstr);
818280849Scy	} else if (cc != (int)size) {
819280849Scy		snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size);
82054359Sroberto		return (errstr);
82154359Sroberto	}
82254359Sroberto	return (NULL);
82354359Sroberto}
82454359Sroberto
82554359Sroberto/* Request periodic message output */
82654359Srobertostatic struct {
82754359Sroberto	struct jheader jheader;
82854359Sroberto	struct jrequest jrequest;
82954359Sroberto} reqmsg = {
83054359Sroberto	{ putshort(JUPITER_SYNC), 0,
83154359Sroberto	    putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1),
832182007Sroberto	    0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK |
833182007Sroberto	    JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 },
83454359Sroberto	{ 0, 0, 0, 0 }
83554359Sroberto};
83654359Sroberto
83754359Sroberto/* An interval of zero means to output on trigger */
83854359Srobertostatic void
839358659Scyjupiter_reqmsg(
840358659Scy	struct instance * const up,
841358659Scy	u_int                   id,
842358659Scy	u_int             interval
843358659Scy	)
84454359Sroberto{
845132451Sroberto	struct jheader *hp;
846132451Sroberto	struct jrequest *rp;
847132451Sroberto	char *cp;
84854359Sroberto
84954359Sroberto	hp = &reqmsg.jheader;
85054359Sroberto	hp->id = putshort(id);
85154359Sroberto	rp = &reqmsg.jrequest;
85254359Sroberto	rp->trigger = putshort(interval == 0);
85354359Sroberto	rp->interval = putshort(interval);
854358659Scy	if ((cp = jupiter_send(up, hp)) != NULL)
855358659Scy		jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
85654359Sroberto}
85754359Sroberto
85854359Sroberto/* Cancel periodic message output */
85954359Srobertostatic struct jheader canmsg = {
86054359Sroberto	putshort(JUPITER_SYNC), 0, 0, 0,
861182007Sroberto	JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC,
86254359Sroberto	0
86354359Sroberto};
86454359Sroberto
86554359Srobertostatic void
866358659Scyjupiter_canmsg(
867358659Scy	struct instance * const up,
868358659Scy	u_int                   id
869358659Scy	)
87054359Sroberto{
871132451Sroberto	struct jheader *hp;
872132451Sroberto	char *cp;
87354359Sroberto
87454359Sroberto	hp = &canmsg;
87554359Sroberto	hp->id = putshort(id);
876358659Scy	if ((cp = jupiter_send(up, hp)) != NULL)
877358659Scy		jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
87854359Sroberto}
87954359Sroberto
88054359Sroberto/* Request a single message output */
88154359Srobertostatic struct jheader reqonemsg = {
88254359Sroberto	putshort(JUPITER_SYNC), 0, 0, 0,
883182007Sroberto	JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY,
88454359Sroberto	0
88554359Sroberto};
88654359Sroberto
88754359Srobertostatic void
888358659Scyjupiter_reqonemsg(
889358659Scy	struct instance * const up,
890358659Scy	u_int                   id
891358659Scy	)
89254359Sroberto{
893132451Sroberto	struct jheader *hp;
894132451Sroberto	char *cp;
89554359Sroberto
89654359Sroberto	hp = &reqonemsg;
89754359Sroberto	hp->id = putshort(id);
898358659Scy	if ((cp = jupiter_send(up, hp)) != NULL)
899358659Scy		jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
90054359Sroberto}
90154359Sroberto
90254359Sroberto/* Set the platform dynamics */
90354359Srobertostatic struct {
90454359Sroberto	struct jheader jheader;
90554359Sroberto	struct jplat jplat;
90654359Sroberto} platmsg = {
90754359Sroberto	{ putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT),
90854359Sroberto	    putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0,
909182007Sroberto	    JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 },
91054359Sroberto	{ 0, 0, 0 }
91154359Sroberto};
91254359Sroberto
91354359Srobertostatic void
914358659Scyjupiter_platform(
915358659Scy	struct instance * const up,
916358659Scy	u_int             platform
917358659Scy	)
91854359Sroberto{
919132451Sroberto	struct jheader *hp;
920132451Sroberto	struct jplat *pp;
921132451Sroberto	char *cp;
92254359Sroberto
92354359Sroberto	hp = &platmsg.jheader;
92454359Sroberto	pp = &platmsg.jplat;
92554359Sroberto	pp->platform = putshort(platform);
926358659Scy	if ((cp = jupiter_send(up, hp)) != NULL)
927358659Scy		jupiter_debug(up->peer, __func__, "%u: %s", platform, cp);
92854359Sroberto}
92954359Sroberto
93054359Sroberto/* Checksum "len" shorts */
93154359Srobertostatic u_short
932132451Srobertojupiter_cksum(u_short *sp, u_int len)
93354359Sroberto{
934132451Sroberto	u_short sum, x;
93554359Sroberto
93654359Sroberto	sum = 0;
93754359Sroberto	while (len-- > 0) {
93854359Sroberto		x = *sp++;
93954359Sroberto		sum += getshort(x);
94054359Sroberto	}
94154359Sroberto	return (~sum + 1);
94254359Sroberto}
94354359Sroberto
94454359Sroberto/* Return the size of the next message (or zero if we don't have it all yet) */
94554359Srobertostatic int
946358659Scyjupiter_recv(
947358659Scy	struct instance * const up
948358659Scy	)
94954359Sroberto{
950132451Sroberto	int n, len, size, cc;
951132451Sroberto	struct jheader *hp;
952132451Sroberto	u_char *bp;
953132451Sroberto	u_short *sp;
95454359Sroberto
95554359Sroberto	/* Must have at least a header's worth */
95654359Sroberto	cc = sizeof(*hp);
957358659Scy	size = up->ssize;
95854359Sroberto	if (size < cc)
95954359Sroberto		return (0);
96054359Sroberto
96154359Sroberto	/* Search for the sync short if missing */
962358659Scy	sp = up->sbuf;
96354359Sroberto	hp = (struct jheader *)sp;
96454359Sroberto	if (getshort(hp->sync) != JUPITER_SYNC) {
96554359Sroberto		/* Wasn't at the front, sync up */
966358659Scy		jupiter_debug(up->peer, __func__, "syncing");
96754359Sroberto		bp = (u_char *)sp;
96854359Sroberto		n = size;
96954359Sroberto		while (n >= 2) {
97054359Sroberto			if (bp[0] != (JUPITER_SYNC & 0xff)) {
971132451Sroberto				/*
972358659Scy				jupiter_debug(up->peer, __func__,
973280849Scy				    "{0x%x}", bp[0]);
974132451Sroberto				*/
97554359Sroberto				++bp;
97654359Sroberto				--n;
97754359Sroberto				continue;
97854359Sroberto			}
97954359Sroberto			if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
98054359Sroberto				break;
981132451Sroberto			/*
982358659Scy			jupiter_debug(up->peer, __func__,
983280849Scy			    "{0x%x 0x%x}", bp[0], bp[1]);
984132451Sroberto			*/
98554359Sroberto			bp += 2;
98654359Sroberto			n -= 2;
98754359Sroberto		}
988132451Sroberto		/*
989358659Scy		jupiter_debug(up->peer, __func__, "\n");
990132451Sroberto		*/
99154359Sroberto		/* Shuffle data to front of input buffer */
99254359Sroberto		if (n > 0)
99354359Sroberto			memcpy(sp, bp, n);
99454359Sroberto		size = n;
995358659Scy		up->ssize = size;
99654359Sroberto		if (size < cc || hp->sync != JUPITER_SYNC)
99754359Sroberto			return (0);
99854359Sroberto	}
99954359Sroberto
100054359Sroberto	if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
100154359Sroberto	    getshort(hp->hsum)) {
1002358659Scy	    jupiter_debug(up->peer, __func__, "bad header checksum!");
100354359Sroberto		/* This is drastic but checksum errors should be rare */
1004358659Scy		up->ssize = 0;
100554359Sroberto		return (0);
100654359Sroberto	}
100754359Sroberto
100854359Sroberto	/* Check for a payload */
100954359Sroberto	len = getshort(hp->len);
101054359Sroberto	if (len > 0) {
101154359Sroberto		n = (len + 1) * sizeof(u_short);
101254359Sroberto		/* Not enough data yet */
101354359Sroberto		if (size < cc + n)
101454359Sroberto			return (0);
101554359Sroberto
101654359Sroberto		/* Check payload checksum */
101754359Sroberto		sp = (u_short *)(hp + 1);
101854359Sroberto		if (jupiter_cksum(sp, len) != getshort(sp[len])) {
1019358659Scy			jupiter_debug(up->peer,
1020280849Scy			    __func__, "bad payload checksum!");
102154359Sroberto			/* This is drastic but checksum errors should be rare */
1022358659Scy			up->ssize = 0;
102354359Sroberto			return (0);
102454359Sroberto		}
102554359Sroberto		cc += n;
102654359Sroberto	}
102754359Sroberto	return (cc);
102854359Sroberto}
102954359Sroberto
1030132451Sroberto#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
103154359Srobertoint refclock_jupiter_bs;
1032132451Sroberto#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1033