xref: /freebsd/contrib/ntp/ntpd/refclock_jupiter.c (revision 224ba2bd37e182b64f7d78defef8a6cacaad3415)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * Copyright (c) 1997, 1998
3c0b746e5SOllivier Robert  *	The Regents of the University of California.  All rights reserved.
4c0b746e5SOllivier Robert  *
5c0b746e5SOllivier Robert  * Redistribution and use in source and binary forms, with or without
6c0b746e5SOllivier Robert  * modification, are permitted provided that the following conditions
7c0b746e5SOllivier Robert  * are met:
8c0b746e5SOllivier Robert  * 1. Redistributions of source code must retain the above copyright
9c0b746e5SOllivier Robert  *    notice, this list of conditions and the following disclaimer.
10c0b746e5SOllivier Robert  * 2. Redistributions in binary form must reproduce the above copyright
11c0b746e5SOllivier Robert  *    notice, this list of conditions and the following disclaimer in the
12c0b746e5SOllivier Robert  *    documentation and/or other materials provided with the distribution.
13c0b746e5SOllivier Robert  * 3. All advertising materials mentioning features or use of this software
14c0b746e5SOllivier Robert  *    must display the following acknowledgement:
15c0b746e5SOllivier Robert  *	This product includes software developed by the University of
16c0b746e5SOllivier Robert  *	California, Lawrence Berkeley Laboratory.
17c0b746e5SOllivier Robert  * 4. The name of the University may not be used to endorse or promote
18c0b746e5SOllivier Robert  *    products derived from this software without specific prior
19c0b746e5SOllivier Robert  *    written permission.
20c0b746e5SOllivier Robert  *
21c0b746e5SOllivier Robert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22c0b746e5SOllivier Robert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c0b746e5SOllivier Robert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c0b746e5SOllivier Robert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25c0b746e5SOllivier Robert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c0b746e5SOllivier Robert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c0b746e5SOllivier Robert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c0b746e5SOllivier Robert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c0b746e5SOllivier Robert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c0b746e5SOllivier Robert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c0b746e5SOllivier Robert  * SUCH DAMAGE.
32c0b746e5SOllivier Robert  */
33c0b746e5SOllivier Robert 
34c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
35c0b746e5SOllivier Robert # include <config.h>
36c0b746e5SOllivier Robert #endif
37c0b746e5SOllivier Robert 
38c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(PPS)
39c0b746e5SOllivier Robert 
40c0b746e5SOllivier Robert #include "ntpd.h"
41c0b746e5SOllivier Robert #include "ntp_io.h"
42c0b746e5SOllivier Robert #include "ntp_refclock.h"
43c0b746e5SOllivier Robert #include "ntp_unixtime.h"
44c0b746e5SOllivier Robert #include "ntp_stdlib.h"
45c0b746e5SOllivier Robert #include "ntp_calendar.h"
46c0b746e5SOllivier Robert 
47224ba2bdSOllivier Robert #include <stdio.h>
48224ba2bdSOllivier Robert #include <ctype.h>
49224ba2bdSOllivier Robert 
50c0b746e5SOllivier Robert #include "jupiter.h"
51c0b746e5SOllivier Robert 
52c0b746e5SOllivier Robert #include <sys/ppsclock.h>
53c0b746e5SOllivier Robert 
54c0b746e5SOllivier Robert #ifdef XNTP_BIG_ENDIAN
55c0b746e5SOllivier Robert #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
56c0b746e5SOllivier Robert #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
57c0b746e5SOllivier Robert #else
58c0b746e5SOllivier Robert #define getshort(s) (s)
59c0b746e5SOllivier Robert #define putshort(s) (s)
60c0b746e5SOllivier Robert #endif
61c0b746e5SOllivier Robert 
62c0b746e5SOllivier Robert /* XXX */
63c0b746e5SOllivier Robert #ifdef sun
64c0b746e5SOllivier Robert char *strerror(int);
65c0b746e5SOllivier Robert #endif
66c0b746e5SOllivier Robert 
67c0b746e5SOllivier Robert /*
68c0b746e5SOllivier Robert  * This driver supports the Rockwell Jupiter GPS Receiver board
69c0b746e5SOllivier Robert  * adapted to precision timing applications.  It requires the
70c0b746e5SOllivier Robert  * ppsclock line discipline or streams module described in the
71c0b746e5SOllivier Robert  * Line Disciplines and Streams Drivers page. It also requires a
72c0b746e5SOllivier Robert  * gadget box and 1-PPS level converter, such as described in the
73c0b746e5SOllivier Robert  * Pulse-per-second (PPS) Signal Interfacing page.
74c0b746e5SOllivier Robert  *
75c0b746e5SOllivier Robert  * It may work (with minor modifications) with other Rockwell GPS
76c0b746e5SOllivier Robert  * receivers such as the CityTracker.
77c0b746e5SOllivier Robert  */
78c0b746e5SOllivier Robert 
79c0b746e5SOllivier Robert /*
80c0b746e5SOllivier Robert  * GPS Definitions
81c0b746e5SOllivier Robert  */
82c0b746e5SOllivier Robert #define	DEVICE		"/dev/gps%d"	/* device name and unit */
83c0b746e5SOllivier Robert #define	SPEED232	B9600		/* baud */
84c0b746e5SOllivier Robert 
85c0b746e5SOllivier Robert /*
86c0b746e5SOllivier Robert  * The number of raw samples which we acquire to derive a single estimate.
87c0b746e5SOllivier Robert  * NSAMPLES ideally should not exceed the default poll interval 64.
88c0b746e5SOllivier Robert  * NKEEP must be a power of 2 to simplify the averaging process.
89c0b746e5SOllivier Robert  */
90c0b746e5SOllivier Robert #define NSAMPLES	64
91c0b746e5SOllivier Robert #define NKEEP		8
92c0b746e5SOllivier Robert #define REFCLOCKMAXDISPERSE .25	/* max sample dispersion */
93c0b746e5SOllivier Robert 
94c0b746e5SOllivier Robert /*
95c0b746e5SOllivier Robert  * Radio interface parameters
96c0b746e5SOllivier Robert  */
97c0b746e5SOllivier Robert #define	PRECISION	(-18)	/* precision assumed (about 4 us) */
98c0b746e5SOllivier Robert #define	REFID	"GPS\0"		/* reference id */
99c0b746e5SOllivier Robert #define	DESCRIPTION	"Rockwell Jupiter GPS Receiver" /* who we are */
100c0b746e5SOllivier Robert #define	DEFFUDGETIME	0	/* default fudge time (ms) */
101c0b746e5SOllivier Robert 
102c0b746e5SOllivier Robert /* Unix timestamp for the GPS epoch: January 6, 1980 */
103c0b746e5SOllivier Robert #define GPS_EPOCH 315964800
104c0b746e5SOllivier Robert 
105c0b746e5SOllivier Robert /* Double short to unsigned int */
106c0b746e5SOllivier Robert #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
107c0b746e5SOllivier Robert 
108c0b746e5SOllivier Robert /* Double short to signed int */
109c0b746e5SOllivier Robert #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
110c0b746e5SOllivier Robert 
111c0b746e5SOllivier Robert /* One week's worth of seconds */
112c0b746e5SOllivier Robert #define WEEKSECS (7 * 24 * 60 * 60)
113c0b746e5SOllivier Robert 
114c0b746e5SOllivier Robert /*
115c0b746e5SOllivier Robert  * Jupiter unit control structure.
116c0b746e5SOllivier Robert  */
117c0b746e5SOllivier Robert struct jupiterunit {
118c0b746e5SOllivier Robert 	u_int  pollcnt;			/* poll message counter */
119c0b746e5SOllivier Robert 	u_int  polled;			/* Hand in a time sample? */
120c0b746e5SOllivier Robert 	u_int  lastserial;		/* last pps serial number */
121c0b746e5SOllivier Robert 	struct ppsclockev ppsev;	/* PPS control structure */
122c0b746e5SOllivier Robert 	u_int gweek;			/* current GPS week number */
123c0b746e5SOllivier Robert 	u_int32 lastsweek;		/* last seconds into GPS week */
124c0b746e5SOllivier Robert 	u_int32 timecode;		/* current ntp timecode */
125c0b746e5SOllivier Robert 	u_int32 stime;			/* used to detect firmware bug */
126c0b746e5SOllivier Robert 	int wantid;			/* don't reconfig on channel id msg */
127c0b746e5SOllivier Robert 	u_int  moving;			/* mobile platform? */
128c0b746e5SOllivier Robert 	u_long sloppyclockflag;		/* fudge flags */
129c0b746e5SOllivier Robert 	u_int  known;			/* position known yet? */
130c0b746e5SOllivier Robert 	int    coderecv;		/* total received samples */
131c0b746e5SOllivier Robert 	int    nkeep;			/* number of samples to preserve */
132c0b746e5SOllivier Robert 	int    rshift;			/* number of rshifts for division */
133c0b746e5SOllivier Robert 	l_fp   filter[NSAMPLES];	/* offset filter */
134c0b746e5SOllivier Robert 	l_fp   lastref;			/* last reference timestamp */
135c0b746e5SOllivier Robert 	u_short sbuf[512];		/* local input buffer */
136c0b746e5SOllivier Robert 	int ssize;			/* space used in sbuf */
137c0b746e5SOllivier Robert };
138c0b746e5SOllivier Robert 
139c0b746e5SOllivier Robert /*
140c0b746e5SOllivier Robert  * Function prototypes
141c0b746e5SOllivier Robert  */
142c0b746e5SOllivier Robert static	void	jupiter_canmsg	P((struct peer *, u_int));
143c0b746e5SOllivier Robert static	u_short	jupiter_cksum	P((u_short *, u_int));
144c0b746e5SOllivier Robert #ifdef QSORT_USES_VOID_P
145c0b746e5SOllivier Robert 	int	jupiter_cmpl_fp	P((const void *, const void *));
146c0b746e5SOllivier Robert #else
147c0b746e5SOllivier Robert 	int	jupiter_cmpl_fp	P((const l_fp *, const l_fp *));
148c0b746e5SOllivier Robert #endif /* not QSORT_USES_VOID_P */
149c0b746e5SOllivier Robert static	void	jupiter_config	P((struct peer *));
150c0b746e5SOllivier Robert static	void	jupiter_debug	P((struct peer *, char *, ...))
151c0b746e5SOllivier Robert     __attribute__ ((format (printf, 2, 3)));
152c0b746e5SOllivier Robert static	char *	jupiter_offset	P((struct peer *));
153c0b746e5SOllivier Robert static	char *	jupiter_parse_t	P((struct peer *, u_short *));
154c0b746e5SOllivier Robert static	void	jupiter_platform	P((struct peer *, u_int));
155c0b746e5SOllivier Robert static	void	jupiter_poll	P((int, struct peer *));
156c0b746e5SOllivier Robert static	int	jupiter_pps	P((struct peer *));
157c0b746e5SOllivier Robert static	char *	jupiter_process	P((struct peer *));
158c0b746e5SOllivier Robert static	int	jupiter_recv	P((struct peer *));
159c0b746e5SOllivier Robert static	void	jupiter_receive P((register struct recvbuf *rbufp));
160c0b746e5SOllivier Robert static	void	jupiter_reqmsg	P((struct peer *, u_int, u_int));
161c0b746e5SOllivier Robert static	void	jupiter_reqonemsg	P((struct peer *, u_int));
162c0b746e5SOllivier Robert static	char *	jupiter_send	P((struct peer *, struct jheader *));
163c0b746e5SOllivier Robert static	void	jupiter_shutdown	P((int, struct peer *));
164c0b746e5SOllivier Robert static	int	jupiter_start	P((int, struct peer *));
165c0b746e5SOllivier Robert static	int	jupiter_ttyinit	P((struct peer *, int));
166c0b746e5SOllivier Robert 
167c0b746e5SOllivier Robert /*
168c0b746e5SOllivier Robert  * Transfer vector
169c0b746e5SOllivier Robert  */
170c0b746e5SOllivier Robert struct	refclock refclock_jupiter = {
171c0b746e5SOllivier Robert 	jupiter_start,		/* start up driver */
172c0b746e5SOllivier Robert 	jupiter_shutdown,	/* shut down driver */
173c0b746e5SOllivier Robert 	jupiter_poll,		/* transmit poll message */
174c0b746e5SOllivier Robert 	noentry,		/* (clock control) */
175c0b746e5SOllivier Robert 	noentry,		/* (clock init) */
176c0b746e5SOllivier Robert 	noentry,		/* (clock buginfo) */
177c0b746e5SOllivier Robert 	NOFLAGS			/* not used */
178c0b746e5SOllivier Robert };
179c0b746e5SOllivier Robert 
180c0b746e5SOllivier Robert /*
181c0b746e5SOllivier Robert  * jupiter_start - open the devices and initialize data for processing
182c0b746e5SOllivier Robert  */
183c0b746e5SOllivier Robert static int
184c0b746e5SOllivier Robert jupiter_start(
185c0b746e5SOllivier Robert 	register int unit,
186c0b746e5SOllivier Robert 	register struct peer *peer
187c0b746e5SOllivier Robert 	)
188c0b746e5SOllivier Robert {
189c0b746e5SOllivier Robert 	struct refclockproc *pp;
190c0b746e5SOllivier Robert 	register struct jupiterunit *up;
191c0b746e5SOllivier Robert 	register int fd;
192c0b746e5SOllivier Robert 	char gpsdev[20];
193c0b746e5SOllivier Robert 
194c0b746e5SOllivier Robert 	/*
195c0b746e5SOllivier Robert 	 * Open serial port
196c0b746e5SOllivier Robert 	 */
197c0b746e5SOllivier Robert 	(void)sprintf(gpsdev, DEVICE, unit);
198c0b746e5SOllivier Robert 	fd = open(gpsdev, O_RDWR
199c0b746e5SOllivier Robert #ifdef O_NONBLOCK
200c0b746e5SOllivier Robert 	    | O_NONBLOCK
201c0b746e5SOllivier Robert #endif
202c0b746e5SOllivier Robert 	    , 0);
203c0b746e5SOllivier Robert 	if (fd < 0) {
204c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_start: open %s: %s\n",
205c0b746e5SOllivier Robert 		    gpsdev, strerror(errno));
206c0b746e5SOllivier Robert 		return (0);
207c0b746e5SOllivier Robert 	}
208c0b746e5SOllivier Robert 	if (!jupiter_ttyinit(peer, fd))
209c0b746e5SOllivier Robert 		return (0);
210c0b746e5SOllivier Robert 
211c0b746e5SOllivier Robert 	/* Allocate unit structure */
212c0b746e5SOllivier Robert 	if ((up = (struct jupiterunit *)
213c0b746e5SOllivier Robert 	    emalloc(sizeof(struct jupiterunit))) == NULL) {
214c0b746e5SOllivier Robert 		(void) close(fd);
215c0b746e5SOllivier Robert 		return (0);
216c0b746e5SOllivier Robert 	}
217c0b746e5SOllivier Robert 	memset((char *)up, 0, sizeof(struct jupiterunit));
218c0b746e5SOllivier Robert 	pp = peer->procptr;
219c0b746e5SOllivier Robert 	pp->io.clock_recv = jupiter_receive;
220c0b746e5SOllivier Robert 	pp->io.srcclock = (caddr_t)peer;
221c0b746e5SOllivier Robert 	pp->io.datalen = 0;
222c0b746e5SOllivier Robert 	pp->io.fd = fd;
223c0b746e5SOllivier Robert 	if (!io_addclock(&pp->io)) {
224c0b746e5SOllivier Robert 		(void) close(fd);
225c0b746e5SOllivier Robert 		free(up);
226c0b746e5SOllivier Robert 		return (0);
227c0b746e5SOllivier Robert 	}
228c0b746e5SOllivier Robert 	pp->unitptr = (caddr_t)up;
229c0b746e5SOllivier Robert 
230c0b746e5SOllivier Robert 	/*
231c0b746e5SOllivier Robert 	 * Initialize miscellaneous variables
232c0b746e5SOllivier Robert 	 */
233c0b746e5SOllivier Robert 	peer->precision = PRECISION;
234c0b746e5SOllivier Robert 	pp->clockdesc = DESCRIPTION;
235c0b746e5SOllivier Robert 	memcpy((char *)&pp->refid, REFID, 4);
236c0b746e5SOllivier Robert 
237c0b746e5SOllivier Robert 
238c0b746e5SOllivier Robert 	/* Ensure the receiver is properly configured */
239c0b746e5SOllivier Robert 	jupiter_config(peer);
240c0b746e5SOllivier Robert 
241c0b746e5SOllivier Robert 	/* Turn on pulse gathering by requesting the first sample */
242c0b746e5SOllivier Robert 	if (ioctl(fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) {
243c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_ttyinit: CIOGETEV: %s\n",
244c0b746e5SOllivier Robert 		    strerror(errno));
245c0b746e5SOllivier Robert 		(void) close(fd);
246c0b746e5SOllivier Robert 		free(up);
247c0b746e5SOllivier Robert 		return (0);
248c0b746e5SOllivier Robert 	}
249c0b746e5SOllivier Robert 	up->lastserial = up->ppsev.serial;
250c0b746e5SOllivier Robert 	memset(&up->ppsev, 0, sizeof(up->ppsev));
251c0b746e5SOllivier Robert 	return (1);
252c0b746e5SOllivier Robert }
253c0b746e5SOllivier Robert 
254c0b746e5SOllivier Robert /*
255c0b746e5SOllivier Robert  * jupiter_shutdown - shut down the clock
256c0b746e5SOllivier Robert  */
257c0b746e5SOllivier Robert static void
258c0b746e5SOllivier Robert jupiter_shutdown(register int unit, register struct peer *peer)
259c0b746e5SOllivier Robert {
260c0b746e5SOllivier Robert 	register struct jupiterunit *up;
261c0b746e5SOllivier Robert 	struct refclockproc *pp;
262c0b746e5SOllivier Robert 
263c0b746e5SOllivier Robert 	pp = peer->procptr;
264c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
265c0b746e5SOllivier Robert 	io_closeclock(&pp->io);
266c0b746e5SOllivier Robert 	free(up);
267c0b746e5SOllivier Robert }
268c0b746e5SOllivier Robert 
269c0b746e5SOllivier Robert /*
270c0b746e5SOllivier Robert  * jupiter_config - Configure the receiver
271c0b746e5SOllivier Robert  */
272c0b746e5SOllivier Robert static void
273c0b746e5SOllivier Robert jupiter_config(register struct peer *peer)
274c0b746e5SOllivier Robert {
275c0b746e5SOllivier Robert 	register int i;
276c0b746e5SOllivier Robert 	register struct jupiterunit *up;
277c0b746e5SOllivier Robert 	register struct refclockproc *pp;
278c0b746e5SOllivier Robert 
279c0b746e5SOllivier Robert 	pp = peer->procptr;
280c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
281c0b746e5SOllivier Robert 
282c0b746e5SOllivier Robert 	/*
283c0b746e5SOllivier Robert 	 * Initialize the unit variables
284c0b746e5SOllivier Robert 	 *
285c0b746e5SOllivier Robert 	 * STRANGE BEHAVIOUR WARNING: The fudge flags are not available
286c0b746e5SOllivier Robert 	 * at the time jupiter_start is called.  These are set later,
287c0b746e5SOllivier Robert 	 * and so the code must be prepared to handle changing flags.
288c0b746e5SOllivier Robert 	 */
289c0b746e5SOllivier Robert 	up->sloppyclockflag = pp->sloppyclockflag;
290c0b746e5SOllivier Robert 	if (pp->sloppyclockflag & CLK_FLAG2) {
291c0b746e5SOllivier Robert 		up->moving = 1;		/* Receiver on mobile platform */
292c0b746e5SOllivier Robert 		msyslog(LOG_DEBUG, "jupiter_config: mobile platform");
293c0b746e5SOllivier Robert 	} else {
294c0b746e5SOllivier Robert 		up->moving = 0;		/* Static Installation */
295c0b746e5SOllivier Robert 	}
296c0b746e5SOllivier Robert 
297c0b746e5SOllivier Robert 	/* XXX fludge flags don't make the trip from the config to here... */
298c0b746e5SOllivier Robert #ifdef notdef
299c0b746e5SOllivier Robert 	/* Configure for trailing edge triggers */
300c0b746e5SOllivier Robert #ifdef CIOSETTET
301c0b746e5SOllivier Robert 	i = ((pp->sloppyclockflag & CLK_FLAG3) != 0);
302c0b746e5SOllivier Robert 	jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n",
303c0b746e5SOllivier Robert 	    pp->sloppyclockflag);
304c0b746e5SOllivier Robert 	if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0)
305c0b746e5SOllivier Robert 		msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i);
306c0b746e5SOllivier Robert #else
307c0b746e5SOllivier Robert 	if (pp->sloppyclockflag & CLK_FLAG3)
308c0b746e5SOllivier Robert 		msyslog(LOG_DEBUG, "jupiter_configure: \
309c0b746e5SOllivier Robert No kernel support for trailing edge trigger");
310c0b746e5SOllivier Robert #endif
311c0b746e5SOllivier Robert #endif
312c0b746e5SOllivier Robert 
313c0b746e5SOllivier Robert 	up->pollcnt     = 2;
314c0b746e5SOllivier Robert 	up->polled      = 0;
315c0b746e5SOllivier Robert 	up->known       = 0;
316c0b746e5SOllivier Robert 	up->gweek = 0;
317c0b746e5SOllivier Robert 	up->lastsweek = 2 * WEEKSECS;
318c0b746e5SOllivier Robert 	up->timecode = 0;
319c0b746e5SOllivier Robert 	up->stime = 0;
320c0b746e5SOllivier Robert 	up->ssize = 0;
321c0b746e5SOllivier Robert 	up->coderecv    = 0;
322c0b746e5SOllivier Robert 	up->nkeep       = NKEEP;
323c0b746e5SOllivier Robert 	if (up->nkeep > NSAMPLES)
324c0b746e5SOllivier Robert 		up->nkeep = NSAMPLES;
325c0b746e5SOllivier Robert 	if (up->nkeep >= 1)
326c0b746e5SOllivier Robert 		up->rshift = 0;
327c0b746e5SOllivier Robert 	if (up->nkeep >= 2)
328c0b746e5SOllivier Robert 		up->rshift = 1;
329c0b746e5SOllivier Robert 	if (up->nkeep >= 4)
330c0b746e5SOllivier Robert 		up->rshift = 2;
331c0b746e5SOllivier Robert 	if (up->nkeep >= 8)
332c0b746e5SOllivier Robert 		up->rshift = 3;
333c0b746e5SOllivier Robert 	if (up->nkeep >= 16)
334c0b746e5SOllivier Robert 		up->rshift = 4;
335c0b746e5SOllivier Robert 	if (up->nkeep >= 32)
336c0b746e5SOllivier Robert 		up->rshift = 5;
337c0b746e5SOllivier Robert 	if (up->nkeep >= 64)
338c0b746e5SOllivier Robert 		up->rshift = 6;
339c0b746e5SOllivier Robert 	up->nkeep = 1;
340c0b746e5SOllivier Robert 	i = up->rshift;
341c0b746e5SOllivier Robert 	while (i > 0) {
342c0b746e5SOllivier Robert 		up->nkeep *= 2;
343c0b746e5SOllivier Robert 		i--;
344c0b746e5SOllivier Robert 	}
345c0b746e5SOllivier Robert 
346c0b746e5SOllivier Robert 	/* Stop outputting all messages */
347c0b746e5SOllivier Robert 	jupiter_canmsg(peer, JUPITER_ALL);
348c0b746e5SOllivier Robert 
349c0b746e5SOllivier Robert 	/* Request the receiver id so we can syslog the firmware version */
350c0b746e5SOllivier Robert 	jupiter_reqonemsg(peer, JUPITER_O_ID);
351c0b746e5SOllivier Robert 
352c0b746e5SOllivier Robert 	/* Flag that this the id was requested (so we don't get called again) */
353c0b746e5SOllivier Robert 	up->wantid = 1;
354c0b746e5SOllivier Robert 
355c0b746e5SOllivier Robert 	/* Request perodic time mark pulse messages */
356c0b746e5SOllivier Robert 	jupiter_reqmsg(peer, JUPITER_O_PULSE, 1);
357c0b746e5SOllivier Robert 
358c0b746e5SOllivier Robert 	/* Set application platform type */
359c0b746e5SOllivier Robert 	if (up->moving)
360c0b746e5SOllivier Robert 		jupiter_platform(peer, JUPITER_I_PLAT_MED);
361c0b746e5SOllivier Robert 	else
362c0b746e5SOllivier Robert 		jupiter_platform(peer, JUPITER_I_PLAT_LOW);
363c0b746e5SOllivier Robert }
364c0b746e5SOllivier Robert 
365c0b746e5SOllivier Robert /*
366c0b746e5SOllivier Robert  * jupiter_poll - jupiter watchdog routine
367c0b746e5SOllivier Robert  */
368c0b746e5SOllivier Robert static void
369c0b746e5SOllivier Robert jupiter_poll(register int unit, register struct peer *peer)
370c0b746e5SOllivier Robert {
371c0b746e5SOllivier Robert 	register struct jupiterunit *up;
372c0b746e5SOllivier Robert 	register struct refclockproc *pp;
373c0b746e5SOllivier Robert 
374c0b746e5SOllivier Robert 	pp = peer->procptr;
375c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
376c0b746e5SOllivier Robert 
377c0b746e5SOllivier Robert 	/*
378c0b746e5SOllivier Robert 	 * You don't need to poll this clock.  It puts out timecodes
379c0b746e5SOllivier Robert 	 * once per second.  If asked for a timestamp, take note.
380c0b746e5SOllivier Robert 	 * The next time a timecode comes in, it will be fed back.
381c0b746e5SOllivier Robert 	 */
382c0b746e5SOllivier Robert 
383c0b746e5SOllivier Robert 	/*
384c0b746e5SOllivier Robert 	 * If we haven't had a response in a while, reset the receiver.
385c0b746e5SOllivier Robert 	 */
386c0b746e5SOllivier Robert 	if (up->pollcnt > 0) {
387c0b746e5SOllivier Robert 		up->pollcnt--;
388c0b746e5SOllivier Robert 	} else {
389c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_TIMEOUT);
390c0b746e5SOllivier Robert 
391c0b746e5SOllivier Robert 		/* Request the receiver id to trigger a reconfig */
392c0b746e5SOllivier Robert 		jupiter_reqonemsg(peer, JUPITER_O_ID);
393c0b746e5SOllivier Robert 		up->wantid = 0;
394c0b746e5SOllivier Robert 	}
395c0b746e5SOllivier Robert 
396c0b746e5SOllivier Robert 	/*
397c0b746e5SOllivier Robert 	 * polled every 64 seconds. Ask jupiter_receive to hand in
398c0b746e5SOllivier Robert 	 * a timestamp.
399c0b746e5SOllivier Robert 	 */
400c0b746e5SOllivier Robert 	up->polled = 1;
401c0b746e5SOllivier Robert 	pp->polls++;
402c0b746e5SOllivier Robert }
403c0b746e5SOllivier Robert 
404c0b746e5SOllivier Robert /*
405c0b746e5SOllivier Robert  * jupiter_receive - receive gps data
406c0b746e5SOllivier Robert  * Gag me!
407c0b746e5SOllivier Robert  */
408c0b746e5SOllivier Robert static void
409c0b746e5SOllivier Robert jupiter_receive(register struct recvbuf *rbufp)
410c0b746e5SOllivier Robert {
411c0b746e5SOllivier Robert 	register int bpcnt, cc, size, ppsret;
412c0b746e5SOllivier Robert 	register u_int32 last_timecode, laststime;
413c0b746e5SOllivier Robert 	register char *cp;
414c0b746e5SOllivier Robert 	register u_char *bp;
415c0b746e5SOllivier Robert 	register u_short *sp;
416c0b746e5SOllivier Robert 	register u_long sloppyclockflag;
417c0b746e5SOllivier Robert 	register struct jupiterunit *up;
418c0b746e5SOllivier Robert 	register struct jid *ip;
419c0b746e5SOllivier Robert 	register struct jheader *hp;
420c0b746e5SOllivier Robert 	register struct refclockproc *pp;
421c0b746e5SOllivier Robert 	register struct peer *peer;
422c0b746e5SOllivier Robert 
423c0b746e5SOllivier Robert 	/* Initialize pointers and read the timecode and timestamp */
424c0b746e5SOllivier Robert 	peer = (struct peer *)rbufp->recv_srcclock;
425c0b746e5SOllivier Robert 	pp = peer->procptr;
426c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
427c0b746e5SOllivier Robert 
428c0b746e5SOllivier Robert 	/*
429c0b746e5SOllivier Robert 	 * If operating mode has been changed, then reinitialize the receiver
430c0b746e5SOllivier Robert 	 * before doing anything else.
431c0b746e5SOllivier Robert 	 */
432c0b746e5SOllivier Robert /* XXX Sloppy clock flags are broken!! */
433c0b746e5SOllivier Robert 	sloppyclockflag = up->sloppyclockflag;
434c0b746e5SOllivier Robert 	up->sloppyclockflag = pp->sloppyclockflag;
435c0b746e5SOllivier Robert 	if ((pp->sloppyclockflag & CLK_FLAG2) !=
436c0b746e5SOllivier Robert 	    (sloppyclockflag & CLK_FLAG2)) {
437c0b746e5SOllivier Robert 		jupiter_debug(peer,
438c0b746e5SOllivier Robert 		    "jupiter_receive: mode switch: reset receiver\n");
439c0b746e5SOllivier Robert 		jupiter_config(peer);
440c0b746e5SOllivier Robert 		return;
441c0b746e5SOllivier Robert 	}
442c0b746e5SOllivier Robert 
443c0b746e5SOllivier Robert 	up->pollcnt = 2;
444c0b746e5SOllivier Robert 
445c0b746e5SOllivier Robert 	bp = (u_char *)rbufp->recv_buffer;
446c0b746e5SOllivier Robert 	bpcnt = rbufp->recv_length;
447c0b746e5SOllivier Robert 
448c0b746e5SOllivier Robert 	/* This shouldn't happen */
449c0b746e5SOllivier Robert 	if (bpcnt > sizeof(up->sbuf) - up->ssize)
450c0b746e5SOllivier Robert 		bpcnt = sizeof(up->sbuf) - up->ssize;
451c0b746e5SOllivier Robert 
452c0b746e5SOllivier Robert 	/* Append to input buffer */
453c0b746e5SOllivier Robert 	memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt);
454c0b746e5SOllivier Robert 	up->ssize += bpcnt;
455c0b746e5SOllivier Robert 
456c0b746e5SOllivier Robert 	/* While there's at least a header and we parse a intact message */
457c0b746e5SOllivier Robert 	while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) {
458c0b746e5SOllivier Robert 		hp = (struct jheader *)up->sbuf;
459c0b746e5SOllivier Robert 		sp = (u_short *)(hp + 1);
460c0b746e5SOllivier Robert 		size = cc - sizeof(*hp);
461c0b746e5SOllivier Robert 		switch (getshort(hp->id)) {
462c0b746e5SOllivier Robert 
463c0b746e5SOllivier Robert 		case JUPITER_O_PULSE:
464c0b746e5SOllivier Robert 			if (size != sizeof(struct jpulse)) {
465c0b746e5SOllivier Robert 				jupiter_debug(peer,
466c0b746e5SOllivier Robert 				    "jupiter_receive: pulse: len %d != %u\n",
467c0b746e5SOllivier Robert 				    size, (int)sizeof(struct jpulse));
468c0b746e5SOllivier Robert 				refclock_report(peer, CEVNT_BADREPLY);
469c0b746e5SOllivier Robert 				break;
470c0b746e5SOllivier Robert 			}
471c0b746e5SOllivier Robert 
472c0b746e5SOllivier Robert 			/*
473c0b746e5SOllivier Robert 			 * There appears to be a firmware bug related
474c0b746e5SOllivier Robert 			 * to the pulse message; in addition to the one
475c0b746e5SOllivier Robert 			 * per second messages, we get an extra pulse
476c0b746e5SOllivier Robert 			 * message once an hour (on the anniversary of
477c0b746e5SOllivier Robert 			 * the cold start). It seems to come 200 ms
478c0b746e5SOllivier Robert 			 * after the one requested. So if we've seen a
479c0b746e5SOllivier Robert 			 * pulse message in the last 210 ms, we skip
480c0b746e5SOllivier Robert 			 * this one.
481c0b746e5SOllivier Robert 			 */
482c0b746e5SOllivier Robert 			laststime = up->stime;
483c0b746e5SOllivier Robert 			up->stime = DS2UI(((struct jpulse *)sp)->stime);
484c0b746e5SOllivier Robert 			if (laststime != 0 && up->stime - laststime <= 21) {
485c0b746e5SOllivier Robert 				jupiter_debug(peer, "jupiter_receive: \
486c0b746e5SOllivier Robert avoided firmware bug (stime %.2f, laststime %.2f)\n",
487c0b746e5SOllivier Robert     (double)up->stime * 0.01, (double)laststime * 0.01);
488c0b746e5SOllivier Robert 				break;
489c0b746e5SOllivier Robert 			}
490c0b746e5SOllivier Robert 
491c0b746e5SOllivier Robert 			/* Retrieve pps timestamp */
492c0b746e5SOllivier Robert 			ppsret = jupiter_pps(peer);
493c0b746e5SOllivier Robert 
494c0b746e5SOllivier Robert 			/* Parse timecode (even when there's no pps) */
495c0b746e5SOllivier Robert 			last_timecode = up->timecode;
496c0b746e5SOllivier Robert 			if ((cp = jupiter_parse_t(peer, sp)) != NULL) {
497c0b746e5SOllivier Robert 				jupiter_debug(peer,
498c0b746e5SOllivier Robert 				    "jupiter_receive: pulse: %s\n", cp);
499c0b746e5SOllivier Robert 				break;
500c0b746e5SOllivier Robert 			}
501c0b746e5SOllivier Robert 
502c0b746e5SOllivier Robert 			/* Bail if we didn't get a pps timestamp */
503c0b746e5SOllivier Robert 			if (ppsret)
504c0b746e5SOllivier Robert 				break;
505c0b746e5SOllivier Robert 
506c0b746e5SOllivier Robert 			/* Bail if we don't have the last timecode yet */
507c0b746e5SOllivier Robert 			if (last_timecode == 0)
508c0b746e5SOllivier Robert 				break;
509c0b746e5SOllivier Robert 
510c0b746e5SOllivier Robert 			/* Add the new sample to a median filter */
511c0b746e5SOllivier Robert 			if ((cp = jupiter_offset(peer)) != NULL) {
512c0b746e5SOllivier Robert 				jupiter_debug(peer,
513c0b746e5SOllivier Robert 				    "jupiter_receive: offset: %s\n", cp);
514c0b746e5SOllivier Robert 				refclock_report(peer, CEVNT_BADTIME);
515c0b746e5SOllivier Robert 				break;
516c0b746e5SOllivier Robert 			}
517c0b746e5SOllivier Robert 
518c0b746e5SOllivier Robert 			/*
519c0b746e5SOllivier Robert 			 * The clock will blurt a timecode every second
520c0b746e5SOllivier Robert 			 * but we only want one when polled.  If we
521c0b746e5SOllivier Robert 			 * havn't been polled, bail out.
522c0b746e5SOllivier Robert 			 */
523c0b746e5SOllivier Robert 			if (!up->polled)
524c0b746e5SOllivier Robert 				break;
525c0b746e5SOllivier Robert 
526c0b746e5SOllivier Robert 			/*
527c0b746e5SOllivier Robert 			 * It's a live one!  Remember this time.
528c0b746e5SOllivier Robert 			 */
529c0b746e5SOllivier Robert 			pp->lasttime = current_time;
530c0b746e5SOllivier Robert 
531c0b746e5SOllivier Robert 			/*
532c0b746e5SOllivier Robert 			 * Determine the reference clock offset and
533c0b746e5SOllivier Robert 			 * dispersion. NKEEP of NSAMPLE offsets are
534c0b746e5SOllivier Robert 			 * passed through a median filter.
535c0b746e5SOllivier Robert 			 * Save the (filtered) offset and dispersion in
536c0b746e5SOllivier Robert 			 * pp->offset and pp->disp.
537c0b746e5SOllivier Robert 			 */
538c0b746e5SOllivier Robert 			if ((cp = jupiter_process(peer)) != NULL) {
539c0b746e5SOllivier Robert 				jupiter_debug(peer,
540c0b746e5SOllivier Robert 				    "jupiter_receive: process: %s\n", cp);
541c0b746e5SOllivier Robert 				refclock_report(peer, CEVNT_BADTIME);
542c0b746e5SOllivier Robert 				break;
543c0b746e5SOllivier Robert 			}
544c0b746e5SOllivier Robert 			/*
545c0b746e5SOllivier Robert 			 * Return offset and dispersion to control
546c0b746e5SOllivier Robert 			 * module. We use lastrec as both the reference
547c0b746e5SOllivier Robert 			 * time and receive time in order to avoid
548c0b746e5SOllivier Robert 			 * being cute, like setting the reference time
549c0b746e5SOllivier Robert 			 * later than the receive time, which may cause
550c0b746e5SOllivier Robert 			 * a paranoid protocol module to chuck out the
551c0b746e5SOllivier Robert 			 * data.
552c0b746e5SOllivier Robert 			 */
553c0b746e5SOllivier Robert 			jupiter_debug(peer,
554c0b746e5SOllivier Robert 			    "jupiter_receive: process time: \
555c0b746e5SOllivier Robert %4d-%03d %02d:%02d:%02d at %s, %s\n",
556c0b746e5SOllivier Robert 			    pp->year, pp->day,
557c0b746e5SOllivier Robert 			    pp->hour, pp->minute, pp->second,
558c0b746e5SOllivier Robert 			    prettydate(&pp->lastrec), lfptoa(&pp->offset, 6));
559c0b746e5SOllivier Robert 
560c0b746e5SOllivier Robert 			refclock_receive(peer);
561c0b746e5SOllivier Robert 
562c0b746e5SOllivier Robert 			/*
563c0b746e5SOllivier Robert 			 * We have succeeded in answering the poll.
564c0b746e5SOllivier Robert 			 * Turn off the flag and return
565c0b746e5SOllivier Robert 			 */
566c0b746e5SOllivier Robert 			up->polled = 0;
567c0b746e5SOllivier Robert 			break;
568c0b746e5SOllivier Robert 
569c0b746e5SOllivier Robert 		case JUPITER_O_ID:
570c0b746e5SOllivier Robert 			if (size != sizeof(struct jid)) {
571c0b746e5SOllivier Robert 				jupiter_debug(peer,
572c0b746e5SOllivier Robert 				    "jupiter_receive: id: len %d != %u\n",
573c0b746e5SOllivier Robert 				    size, (int)sizeof(struct jid));
574c0b746e5SOllivier Robert 				refclock_report(peer, CEVNT_BADREPLY);
575c0b746e5SOllivier Robert 				break;
576c0b746e5SOllivier Robert 			}
577c0b746e5SOllivier Robert 			/*
578c0b746e5SOllivier Robert 			 * If we got this message because the Jupiter
579c0b746e5SOllivier Robert 			 * just powered up, it needs to be reconfigured.
580c0b746e5SOllivier Robert 			 */
581c0b746e5SOllivier Robert 			ip = (struct jid *)sp;
582c0b746e5SOllivier Robert 			jupiter_debug(peer,
583c0b746e5SOllivier Robert 			    "jupiter_receive: >> %s chan ver %s, %s (%s)\n",
584c0b746e5SOllivier Robert 			    ip->chans, ip->vers, ip->date, ip->opts);
585c0b746e5SOllivier Robert 			msyslog(LOG_DEBUG,
586c0b746e5SOllivier Robert 			    "jupiter_receive: %s chan ver %s, %s (%s)\n",
587c0b746e5SOllivier Robert 			    ip->chans, ip->vers, ip->date, ip->opts);
588c0b746e5SOllivier Robert 			if (up->wantid)
589c0b746e5SOllivier Robert 				up->wantid = 0;
590c0b746e5SOllivier Robert 			else {
591c0b746e5SOllivier Robert 				jupiter_debug(peer,
592c0b746e5SOllivier Robert 				    "jupiter_receive: reset receiver\n");
593c0b746e5SOllivier Robert 				jupiter_config(peer);
594c0b746e5SOllivier Robert 				/* Rese since jupiter_config() just zeroed it */
595c0b746e5SOllivier Robert 				up->ssize = cc;
596c0b746e5SOllivier Robert 			}
597c0b746e5SOllivier Robert 			break;
598c0b746e5SOllivier Robert 
599c0b746e5SOllivier Robert 		default:
600c0b746e5SOllivier Robert 			jupiter_debug(peer,
601c0b746e5SOllivier Robert 			    "jupiter_receive: >> unknown message id %d\n",
602c0b746e5SOllivier Robert 			    getshort(hp->id));
603c0b746e5SOllivier Robert 			break;
604c0b746e5SOllivier Robert 		}
605c0b746e5SOllivier Robert 		up->ssize -= cc;
606c0b746e5SOllivier Robert 		if (up->ssize < 0) {
607c0b746e5SOllivier Robert 			fprintf(stderr, "jupiter_recv: negative ssize!\n");
608c0b746e5SOllivier Robert 			abort();
609c0b746e5SOllivier Robert 		} else if (up->ssize > 0)
610c0b746e5SOllivier Robert 			memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize);
611c0b746e5SOllivier Robert 	}
612c0b746e5SOllivier Robert 	record_clock_stats(&peer->srcadr, "<timecode is binary>");
613c0b746e5SOllivier Robert }
614c0b746e5SOllivier Robert 
615c0b746e5SOllivier Robert /*
616c0b746e5SOllivier Robert  * jupiter_offset - Calculate the offset, and add to the rolling filter.
617c0b746e5SOllivier Robert  */
618c0b746e5SOllivier Robert static char *
619c0b746e5SOllivier Robert jupiter_offset(register struct peer *peer)
620c0b746e5SOllivier Robert {
621c0b746e5SOllivier Robert 	register struct jupiterunit *up;
622c0b746e5SOllivier Robert 	register struct refclockproc *pp;
623c0b746e5SOllivier Robert 	register int i;
624c0b746e5SOllivier Robert 	l_fp offset;
625c0b746e5SOllivier Robert 
626c0b746e5SOllivier Robert 	pp = peer->procptr;
627c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
628c0b746e5SOllivier Robert 
629c0b746e5SOllivier Robert 	/*
630c0b746e5SOllivier Robert 	 * Calculate the offset
631c0b746e5SOllivier Robert 	 */
632c0b746e5SOllivier Robert 	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
633c0b746e5SOllivier Robert 		pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) {
634c0b746e5SOllivier Robert 		return ("jupiter_process: clocktime failed");
635c0b746e5SOllivier Robert 	}
636c0b746e5SOllivier Robert 	if (pp->usec) {
637c0b746e5SOllivier Robert 		TVUTOTSF(pp->usec, offset.l_uf);
638c0b746e5SOllivier Robert 	} else {
639c0b746e5SOllivier Robert 		MSUTOTSF(pp->msec, offset.l_uf);
640c0b746e5SOllivier Robert 	}
641c0b746e5SOllivier Robert 	L_ADD(&offset, &pp->fudgetime1);
642c0b746e5SOllivier Robert 	up->lastref = offset;   /* save last reference time */
643c0b746e5SOllivier Robert 	L_SUB(&offset, &pp->lastrec); /* form true offset */
644c0b746e5SOllivier Robert 
645c0b746e5SOllivier Robert 	/*
646c0b746e5SOllivier Robert 	 * A rolling filter.  Initialize first time around.
647c0b746e5SOllivier Robert 	 */
648c0b746e5SOllivier Robert 	i = ((up->coderecv)) % NSAMPLES;
649c0b746e5SOllivier Robert 
650c0b746e5SOllivier Robert 	up->filter[i] = offset;
651c0b746e5SOllivier Robert 	if (up->coderecv == 0)
652c0b746e5SOllivier Robert 		for (i = 1; (u_int) i < NSAMPLES; i++)
653c0b746e5SOllivier Robert 			up->filter[i] = up->filter[0];
654c0b746e5SOllivier Robert 	up->coderecv++;
655c0b746e5SOllivier Robert 
656c0b746e5SOllivier Robert 	return (NULL);
657c0b746e5SOllivier Robert }
658c0b746e5SOllivier Robert 
659c0b746e5SOllivier Robert /*
660c0b746e5SOllivier Robert  * jupiter_process - process the sample from the clock,
661c0b746e5SOllivier Robert  * passing it through a median filter and optionally averaging
662c0b746e5SOllivier Robert  * the samples.  Returns offset and dispersion in "up" structure.
663c0b746e5SOllivier Robert  */
664c0b746e5SOllivier Robert static char *
665c0b746e5SOllivier Robert jupiter_process(register struct peer *peer)
666c0b746e5SOllivier Robert {
667c0b746e5SOllivier Robert 	register struct jupiterunit *up;
668c0b746e5SOllivier Robert 	register struct refclockproc *pp;
669c0b746e5SOllivier Robert 	register int i, n;
670c0b746e5SOllivier Robert 	register int j, k;
671c0b746e5SOllivier Robert 	l_fp offset, median, lftmp;
672c0b746e5SOllivier Robert 	u_fp disp;
673c0b746e5SOllivier Robert 	l_fp off[NSAMPLES];
674c0b746e5SOllivier Robert 
675c0b746e5SOllivier Robert 	pp = peer->procptr;
676c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
677c0b746e5SOllivier Robert 
678c0b746e5SOllivier Robert 	/*
679c0b746e5SOllivier Robert 	 * Copy the raw offsets and sort into ascending order
680c0b746e5SOllivier Robert 	 */
681c0b746e5SOllivier Robert 	for (i = 0; i < NSAMPLES; i++)
682c0b746e5SOllivier Robert 		off[i] = up->filter[i];
683224ba2bdSOllivier Robert 	qsort((char *)off, (size_t)NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp);
684c0b746e5SOllivier Robert 
685c0b746e5SOllivier Robert 	/*
686c0b746e5SOllivier Robert 	 * Reject the furthest from the median of NSAMPLES samples until
687c0b746e5SOllivier Robert 	 * NKEEP samples remain.
688c0b746e5SOllivier Robert 	 */
689c0b746e5SOllivier Robert 	i = 0;
690c0b746e5SOllivier Robert 	n = NSAMPLES;
691c0b746e5SOllivier Robert 	while ((n - i) > up->nkeep) {
692c0b746e5SOllivier Robert 		lftmp = off[n - 1];
693c0b746e5SOllivier Robert 		median = off[(n + i) / 2];
694c0b746e5SOllivier Robert 		L_SUB(&lftmp, &median);
695c0b746e5SOllivier Robert 		L_SUB(&median, &off[i]);
696c0b746e5SOllivier Robert 		if (L_ISHIS(&median, &lftmp)) {
697c0b746e5SOllivier Robert 			/* reject low end */
698c0b746e5SOllivier Robert 			i++;
699c0b746e5SOllivier Robert 		} else {
700c0b746e5SOllivier Robert 			/* reject high end */
701c0b746e5SOllivier Robert 			n--;
702c0b746e5SOllivier Robert 		}
703c0b746e5SOllivier Robert 	}
704c0b746e5SOllivier Robert 
705c0b746e5SOllivier Robert 	/*
706c0b746e5SOllivier Robert 	 * Copy key values to the billboard to measure performance.
707c0b746e5SOllivier Robert 	 */
708c0b746e5SOllivier Robert 	pp->lastref = up->lastref;
709c0b746e5SOllivier Robert 	pp->coderecv = up->coderecv;
710c0b746e5SOllivier Robert 	pp->filter[0] = off[0];			/* smallest offset */
711c0b746e5SOllivier Robert 	pp->filter[1] = off[NSAMPLES-1];	/* largest offset */
712c0b746e5SOllivier Robert 	for (j = 2, k = i; k < n; j++, k++)
713c0b746e5SOllivier Robert 		pp->filter[j] = off[k];		/* offsets actually examined */
714c0b746e5SOllivier Robert 
715c0b746e5SOllivier Robert 	/*
716c0b746e5SOllivier Robert 	 * Compute the dispersion based on the difference between the
717c0b746e5SOllivier Robert 	 * extremes of the remaining offsets. Add to this the time since
718c0b746e5SOllivier Robert 	 * the last clock update, which represents the dispersion
719c0b746e5SOllivier Robert 	 * increase with time. We know that NTP_MAXSKEW is 16. If the
720c0b746e5SOllivier Robert 	 * sum is greater than the allowed sample dispersion, bail out.
721c0b746e5SOllivier Robert 	 * If the loop is unlocked, return the most recent offset;
722c0b746e5SOllivier Robert 	 * otherwise, return the median offset.
723c0b746e5SOllivier Robert 	 */
724c0b746e5SOllivier Robert 	lftmp = off[n - 1];
725c0b746e5SOllivier Robert 	L_SUB(&lftmp, &off[i]);
726c0b746e5SOllivier Robert 	disp = LFPTOFP(&lftmp);
727c0b746e5SOllivier Robert 	if (disp > REFCLOCKMAXDISPERSE)
728c0b746e5SOllivier Robert 		return ("Maximum dispersion exceeded");
729c0b746e5SOllivier Robert 
730c0b746e5SOllivier Robert 	/*
731c0b746e5SOllivier Robert 	 * Now compute the offset estimate.  If fudge flag 1
732c0b746e5SOllivier Robert 	 * is set, average the remainder, otherwise pick the
733c0b746e5SOllivier Robert 	 * median.
734c0b746e5SOllivier Robert 	 */
735c0b746e5SOllivier Robert 	if (pp->sloppyclockflag & CLK_FLAG1) {
736c0b746e5SOllivier Robert 		L_CLR(&lftmp);
737c0b746e5SOllivier Robert 		while (i < n) {
738c0b746e5SOllivier Robert 			L_ADD(&lftmp, &off[i]);
739c0b746e5SOllivier Robert 			i++;
740c0b746e5SOllivier Robert 		}
741c0b746e5SOllivier Robert 		i = up->rshift;
742c0b746e5SOllivier Robert 		while (i > 0) {
743c0b746e5SOllivier Robert 			L_RSHIFT(&lftmp);
744c0b746e5SOllivier Robert 			i--;
745c0b746e5SOllivier Robert 		}
746c0b746e5SOllivier Robert 		offset = lftmp;
747c0b746e5SOllivier Robert 	} else {
748c0b746e5SOllivier Robert 		i = (n + i) / 2;
749c0b746e5SOllivier Robert 		offset = off[i];
750c0b746e5SOllivier Robert 	}
751c0b746e5SOllivier Robert 
752c0b746e5SOllivier Robert 	/*
753c0b746e5SOllivier Robert 	 * The payload: filtered offset and dispersion.
754c0b746e5SOllivier Robert 	 */
755c0b746e5SOllivier Robert 
756c0b746e5SOllivier Robert 	pp->offset = offset;
757c0b746e5SOllivier Robert 	pp->disp = disp;
758c0b746e5SOllivier Robert 
759c0b746e5SOllivier Robert 	return (NULL);
760c0b746e5SOllivier Robert 
761c0b746e5SOllivier Robert }
762c0b746e5SOllivier Robert 
763c0b746e5SOllivier Robert /* Compare two l_fp's, used with qsort() */
764c0b746e5SOllivier Robert #ifdef QSORT_USES_VOID_P
765a151a66cSOllivier Robert int
766c0b746e5SOllivier Robert jupiter_cmpl_fp(register const void *p1, register const void *p2)
767c0b746e5SOllivier Robert #else
768a151a66cSOllivier Robert int
769c0b746e5SOllivier Robert jupiter_cmpl_fp(register const l_fp *fp1, register const l_fp *fp2)
770c0b746e5SOllivier Robert #endif
771c0b746e5SOllivier Robert {
772c0b746e5SOllivier Robert #ifdef QSORT_USES_VOID_P
773c0b746e5SOllivier Robert 	register const l_fp *fp1 = (const l_fp *)p1;
774c0b746e5SOllivier Robert 	register const l_fp *fp2 = (const l_fp *)p2;
775c0b746e5SOllivier Robert #endif
776c0b746e5SOllivier Robert 
777c0b746e5SOllivier Robert 	if (!L_ISGEQ(fp1, fp2))
778c0b746e5SOllivier Robert 		return (-1);
779c0b746e5SOllivier Robert 	if (L_ISEQU(fp1, fp2))
780c0b746e5SOllivier Robert 		return (0);
781c0b746e5SOllivier Robert 	return (1);
782c0b746e5SOllivier Robert }
783c0b746e5SOllivier Robert 
784c0b746e5SOllivier Robert static char *
785c0b746e5SOllivier Robert jupiter_parse_t(register struct peer *peer, register u_short *sp)
786c0b746e5SOllivier Robert {
787c0b746e5SOllivier Robert 	register struct refclockproc *pp;
788c0b746e5SOllivier Robert 	register struct jupiterunit *up;
789c0b746e5SOllivier Robert 	register struct tm *tm;
790c0b746e5SOllivier Robert 	register char *cp;
791c0b746e5SOllivier Robert 	register struct jpulse *jp;
792c0b746e5SOllivier Robert 	register struct calendar *jt;
793c0b746e5SOllivier Robert 	register u_int32 sweek;
794c0b746e5SOllivier Robert 	register u_int32 last_timecode;
795c0b746e5SOllivier Robert 	register u_short flags;
796c0b746e5SOllivier Robert 	time_t t;
797c0b746e5SOllivier Robert 	struct calendar cal;
798c0b746e5SOllivier Robert 
799c0b746e5SOllivier Robert 	pp = peer->procptr;
800c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
801c0b746e5SOllivier Robert 	jp = (struct jpulse *)sp;
802c0b746e5SOllivier Robert 
803c0b746e5SOllivier Robert 	/* The timecode is presented as seconds into the current GPS week */
804c0b746e5SOllivier Robert 	sweek = DS2UI(jp->sweek);
805c0b746e5SOllivier Robert 
806c0b746e5SOllivier Robert 	/*
807c0b746e5SOllivier Robert 	 * If we don't know the current GPS week, calculate it from the
808c0b746e5SOllivier Robert 	 * current time. (It's too bad they didn't include this
809c0b746e5SOllivier Robert 	 * important value in the pulse message). We'd like to pick it
810c0b746e5SOllivier Robert 	 * up from one of the other messages like gpos or chan but they
811c0b746e5SOllivier Robert 	 * don't appear to be synchronous with time keeping and changes
812c0b746e5SOllivier Robert 	 * too soon (something like 10 seconds before the new GPS
813c0b746e5SOllivier Robert 	 * week).
814c0b746e5SOllivier Robert 	 *
815c0b746e5SOllivier Robert 	 * If we already know the current GPS week, increment it when
816c0b746e5SOllivier Robert 	 * we wrap into a new week.
817c0b746e5SOllivier Robert 	 */
818c0b746e5SOllivier Robert 	if (up->gweek == 0)
819c0b746e5SOllivier Robert 		up->gweek = (time(NULL) - GPS_EPOCH) / WEEKSECS;
820c0b746e5SOllivier Robert 	else if (sweek == 0 && up->lastsweek == WEEKSECS - 1) {
821c0b746e5SOllivier Robert 		++up->gweek;
822c0b746e5SOllivier Robert 		jupiter_debug(peer,
823c0b746e5SOllivier Robert 		    "jupiter_parse_t: NEW gps week %u\n", up->gweek);
824c0b746e5SOllivier Robert 	}
825c0b746e5SOllivier Robert 
826c0b746e5SOllivier Robert 	/*
827c0b746e5SOllivier Robert 	 * See if the sweek stayed the same (this happens when there is
828c0b746e5SOllivier Robert 	 * no pps pulse).
829c0b746e5SOllivier Robert 	 *
830c0b746e5SOllivier Robert 	 * Otherwise, look for time warps:
831c0b746e5SOllivier Robert 	 *
832c0b746e5SOllivier Robert 	 *   - we have stored at least one lastsweek and
833c0b746e5SOllivier Robert 	 *   - the sweek didn't increase by one and
834c0b746e5SOllivier Robert 	 *   - we didn't wrap to a new GPS week
835c0b746e5SOllivier Robert 	 *
836c0b746e5SOllivier Robert 	 * Then we warped.
837c0b746e5SOllivier Robert 	 */
838c0b746e5SOllivier Robert 	if (up->lastsweek == sweek)
839c0b746e5SOllivier Robert 		jupiter_debug(peer,
840c0b746e5SOllivier Robert 		    "jupiter_parse_t: gps sweek not incrementing (%d)\n",
841c0b746e5SOllivier Robert 		    sweek);
842c0b746e5SOllivier Robert 	else if (up->lastsweek != 2 * WEEKSECS &&
843c0b746e5SOllivier Robert 	    up->lastsweek + 1 != sweek &&
844c0b746e5SOllivier Robert 	    !(sweek == 0 && up->lastsweek == WEEKSECS - 1))
845c0b746e5SOllivier Robert 		jupiter_debug(peer,
846c0b746e5SOllivier Robert 		    "jupiter_parse_t: gps sweek jumped (was %d, now %d)\n",
847c0b746e5SOllivier Robert 		    up->lastsweek, sweek);
848c0b746e5SOllivier Robert 	up->lastsweek = sweek;
849c0b746e5SOllivier Robert 
850c0b746e5SOllivier Robert 	/* This timecode describes next pulse */
851c0b746e5SOllivier Robert 	last_timecode = up->timecode;
852c0b746e5SOllivier Robert 	up->timecode = (u_int32)JAN_1970 +
853c0b746e5SOllivier Robert 	    GPS_EPOCH + (up->gweek * WEEKSECS) + sweek;
854c0b746e5SOllivier Robert 
855c0b746e5SOllivier Robert 	if (last_timecode == 0)
856c0b746e5SOllivier Robert 		/* XXX debugging */
857c0b746e5SOllivier Robert 		jupiter_debug(peer,
858c0b746e5SOllivier Robert 		    "jupiter_parse_t: UTC <none> (gweek/sweek %u/%u)\n",
859c0b746e5SOllivier Robert 		    up->gweek, sweek);
860c0b746e5SOllivier Robert 	else {
861c0b746e5SOllivier Robert 		/* XXX debugging */
862c0b746e5SOllivier Robert 		t = last_timecode - (u_int32)JAN_1970;
863c0b746e5SOllivier Robert 		tm = gmtime(&t);
864c0b746e5SOllivier Robert 		cp = asctime(tm);
865c0b746e5SOllivier Robert 
866c0b746e5SOllivier Robert 		jupiter_debug(peer,
867c0b746e5SOllivier Robert 		    "jupiter_parse_t: UTC %.24s (gweek/sweek %u/%u)\n",
868c0b746e5SOllivier Robert 		    cp, up->gweek, sweek);
869c0b746e5SOllivier Robert 
870c0b746e5SOllivier Robert 		/* Billboard last_timecode (which is now the current time) */
871c0b746e5SOllivier Robert 		jt = &cal;
872c0b746e5SOllivier Robert 		caljulian(last_timecode, jt);
873c0b746e5SOllivier Robert 		pp = peer->procptr;
874c0b746e5SOllivier Robert 		pp->year = jt->year;
875c0b746e5SOllivier Robert 		pp->day = jt->yearday;
876c0b746e5SOllivier Robert 		pp->hour = jt->hour;
877c0b746e5SOllivier Robert 		pp->minute = jt->minute;
878c0b746e5SOllivier Robert 		pp->second = jt->second;
879c0b746e5SOllivier Robert 		pp->msec = 0;
880c0b746e5SOllivier Robert 		pp->usec = 0;
881c0b746e5SOllivier Robert 	}
882c0b746e5SOllivier Robert 
883c0b746e5SOllivier Robert 	/* XXX debugging */
884c0b746e5SOllivier Robert 	tm = gmtime(&up->ppsev.tv.tv_sec);
885c0b746e5SOllivier Robert 	cp = asctime(tm);
886c0b746e5SOllivier Robert 	flags = getshort(jp->flags);
887c0b746e5SOllivier Robert 	jupiter_debug(peer,
888c0b746e5SOllivier Robert 	    "jupiter_parse_t: PPS %.19s.%06lu %.4s (serial %u)%s\n",
889c0b746e5SOllivier Robert 	    cp, up->ppsev.tv.tv_usec, cp + 20, up->ppsev.serial,
890c0b746e5SOllivier Robert 	    (flags & JUPITER_O_PULSE_VALID) == 0 ?
891c0b746e5SOllivier Robert 	    " NOT VALID" : "");
892c0b746e5SOllivier Robert 
893c0b746e5SOllivier Robert 	/* Toss if not designated "valid" by the gps */
894c0b746e5SOllivier Robert 	if ((flags & JUPITER_O_PULSE_VALID) == 0) {
895c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADTIME);
896c0b746e5SOllivier Robert 		return ("time mark not valid");
897c0b746e5SOllivier Robert 	}
898c0b746e5SOllivier Robert 
899c0b746e5SOllivier Robert 	/* We better be sync'ed to UTC... */
900c0b746e5SOllivier Robert 	if ((flags & JUPITER_O_PULSE_UTC) == 0) {
901c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADTIME);
902c0b746e5SOllivier Robert 		return ("time mark not sync'ed to UTC");
903c0b746e5SOllivier Robert 	}
904c0b746e5SOllivier Robert 
905c0b746e5SOllivier Robert 	return (NULL);
906c0b746e5SOllivier Robert }
907c0b746e5SOllivier Robert 
908c0b746e5SOllivier Robert /*
909c0b746e5SOllivier Robert  * Process a PPS signal, returning a timestamp.
910c0b746e5SOllivier Robert  */
911c0b746e5SOllivier Robert static int
912c0b746e5SOllivier Robert jupiter_pps(register struct peer *peer)
913c0b746e5SOllivier Robert {
914c0b746e5SOllivier Robert 	register struct refclockproc *pp;
915c0b746e5SOllivier Robert 	register struct jupiterunit *up;
916c0b746e5SOllivier Robert 	register int firsttime;
917c0b746e5SOllivier Robert 	struct timeval ntp_tv;
918c0b746e5SOllivier Robert 
919c0b746e5SOllivier Robert 	pp = peer->procptr;
920c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
921c0b746e5SOllivier Robert 
922c0b746e5SOllivier Robert 	/*
923c0b746e5SOllivier Robert 	 * Grab the timestamp of the PPS signal.
924c0b746e5SOllivier Robert 	 */
925c0b746e5SOllivier Robert 	firsttime = (up->ppsev.tv.tv_sec == 0);
926c0b746e5SOllivier Robert 	if (ioctl(pp->io.fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) {
927c0b746e5SOllivier Robert 		/* XXX Actually, if this fails, we're pretty much screwed */
928c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_pps: CIOGETEV: %s\n",
929c0b746e5SOllivier Robert 		    strerror(errno));
930c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_FAULT);
931c0b746e5SOllivier Robert 		return (1);
932c0b746e5SOllivier Robert 	}
933c0b746e5SOllivier Robert 
934c0b746e5SOllivier Robert 	/*
935c0b746e5SOllivier Robert 	 * Check pps serial number against last one
936c0b746e5SOllivier Robert 	 */
937c0b746e5SOllivier Robert 	if (!firsttime && up->lastserial + 1 != up->ppsev.serial) {
938c0b746e5SOllivier Robert 		if (up->ppsev.serial == up->lastserial)
939c0b746e5SOllivier Robert 			jupiter_debug(peer, "jupiter_pps: no new pps event\n");
940c0b746e5SOllivier Robert 		else
941c0b746e5SOllivier Robert 			jupiter_debug(peer,
942c0b746e5SOllivier Robert 			    "jupiter_pps: missed %d pps events\n",
943c0b746e5SOllivier Robert 				up->ppsev.serial - up->lastserial - 1);
944c0b746e5SOllivier Robert 		up->lastserial = up->ppsev.serial;
945c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_FAULT);
946c0b746e5SOllivier Robert 		return (1);
947c0b746e5SOllivier Robert 	}
948c0b746e5SOllivier Robert 	up->lastserial = up->ppsev.serial;
949c0b746e5SOllivier Robert 
950c0b746e5SOllivier Robert 	/*
951c0b746e5SOllivier Robert 	 * Return the timestamp in pp->lastrec
952c0b746e5SOllivier Robert 	 */
953c0b746e5SOllivier Robert 	ntp_tv = up->ppsev.tv;
954c0b746e5SOllivier Robert 	ntp_tv.tv_sec += (u_int32)JAN_1970;
955c0b746e5SOllivier Robert 	TVTOTS(&ntp_tv, &pp->lastrec);
956c0b746e5SOllivier Robert 
957c0b746e5SOllivier Robert 	return (0);
958c0b746e5SOllivier Robert }
959c0b746e5SOllivier Robert 
960c0b746e5SOllivier Robert /*
961c0b746e5SOllivier Robert  * jupiter_debug - print debug messages
962c0b746e5SOllivier Robert  */
963a151a66cSOllivier Robert #if defined(__STDC__)
964c0b746e5SOllivier Robert static void
965c0b746e5SOllivier Robert jupiter_debug(struct peer *peer, char *fmt, ...)
966c0b746e5SOllivier Robert #else
967c0b746e5SOllivier Robert static void
968c0b746e5SOllivier Robert jupiter_debug(peer, fmt, va_alist)
969c0b746e5SOllivier Robert 	struct peer *peer;
970c0b746e5SOllivier Robert 	char *fmt;
971a151a66cSOllivier Robert #endif /* __STDC__ */
972c0b746e5SOllivier Robert {
973c0b746e5SOllivier Robert 	va_list ap;
974c0b746e5SOllivier Robert 
975c0b746e5SOllivier Robert 	if (debug) {
976c0b746e5SOllivier Robert 
977a151a66cSOllivier Robert #if defined(__STDC__)
978c0b746e5SOllivier Robert 		va_start(ap, fmt);
979c0b746e5SOllivier Robert #else
980c0b746e5SOllivier Robert 		va_start(ap);
981a151a66cSOllivier Robert #endif /* __STDC__ */
982c0b746e5SOllivier Robert 		/*
983c0b746e5SOllivier Robert 		 * Print debug message to stdout
984c0b746e5SOllivier Robert 		 * In the future, we may want to get get more creative...
985c0b746e5SOllivier Robert 		 */
986c0b746e5SOllivier Robert 		vfprintf(stderr, fmt, ap);
987c0b746e5SOllivier Robert 
988c0b746e5SOllivier Robert 		va_end(ap);
989c0b746e5SOllivier Robert 	}
990c0b746e5SOllivier Robert }
991c0b746e5SOllivier Robert 
992c0b746e5SOllivier Robert /* Checksum and transmit a message to the Jupiter */
993c0b746e5SOllivier Robert static char *
994c0b746e5SOllivier Robert jupiter_send(register struct peer *peer, register struct jheader *hp)
995c0b746e5SOllivier Robert {
996c0b746e5SOllivier Robert 	register u_int len, size;
997c0b746e5SOllivier Robert 	register int cc;
998c0b746e5SOllivier Robert 	register u_short *sp;
999c0b746e5SOllivier Robert 	static char errstr[132];
1000c0b746e5SOllivier Robert 
1001c0b746e5SOllivier Robert 	size = sizeof(*hp);
1002c0b746e5SOllivier Robert 	hp->hsum = putshort(jupiter_cksum((u_short *)hp,
1003c0b746e5SOllivier Robert 	    (size / sizeof(u_short)) - 1));
1004c0b746e5SOllivier Robert 	len = getshort(hp->len);
1005c0b746e5SOllivier Robert 	if (len > 0) {
1006c0b746e5SOllivier Robert 		sp = (u_short *)(hp + 1);
1007c0b746e5SOllivier Robert 		sp[len] = putshort(jupiter_cksum(sp, len));
1008c0b746e5SOllivier Robert 		size += (len + 1) * sizeof(u_short);
1009c0b746e5SOllivier Robert 	}
1010c0b746e5SOllivier Robert 
1011c0b746e5SOllivier Robert 	if ((cc = write(peer->procptr->io.fd, (char *)hp, size)) < 0) {
1012c0b746e5SOllivier Robert 		(void)sprintf(errstr, "write: %s", strerror(errno));
1013c0b746e5SOllivier Robert 		return (errstr);
1014c0b746e5SOllivier Robert 	} else if (cc != size) {
1015c0b746e5SOllivier Robert 		(void)sprintf(errstr, "short write (%d != %d)", cc, size);
1016c0b746e5SOllivier Robert 		return (errstr);
1017c0b746e5SOllivier Robert 	}
1018c0b746e5SOllivier Robert 	return (NULL);
1019c0b746e5SOllivier Robert }
1020c0b746e5SOllivier Robert 
1021c0b746e5SOllivier Robert /* Request periodic message output */
1022c0b746e5SOllivier Robert static struct {
1023c0b746e5SOllivier Robert 	struct jheader jheader;
1024c0b746e5SOllivier Robert 	struct jrequest jrequest;
1025c0b746e5SOllivier Robert } reqmsg = {
1026c0b746e5SOllivier Robert 	{ putshort(JUPITER_SYNC), 0,
1027c0b746e5SOllivier Robert 	    putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1),
1028c0b746e5SOllivier Robert 	    0, putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK |
1029c0b746e5SOllivier Robert 	    JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 },
1030c0b746e5SOllivier Robert 	{ 0, 0, 0, 0 }
1031c0b746e5SOllivier Robert };
1032c0b746e5SOllivier Robert 
1033c0b746e5SOllivier Robert /* An interval of zero means to output on trigger */
1034c0b746e5SOllivier Robert static void
1035c0b746e5SOllivier Robert jupiter_reqmsg(register struct peer *peer, register u_int id,
1036c0b746e5SOllivier Robert     register u_int interval)
1037c0b746e5SOllivier Robert {
1038c0b746e5SOllivier Robert 	register struct jheader *hp;
1039c0b746e5SOllivier Robert 	register struct jrequest *rp;
1040c0b746e5SOllivier Robert 	register char *cp;
1041c0b746e5SOllivier Robert 
1042c0b746e5SOllivier Robert 	hp = &reqmsg.jheader;
1043c0b746e5SOllivier Robert 	hp->id = putshort(id);
1044c0b746e5SOllivier Robert 	rp = &reqmsg.jrequest;
1045c0b746e5SOllivier Robert 	rp->trigger = putshort(interval == 0);
1046c0b746e5SOllivier Robert 	rp->interval = putshort(interval);
1047c0b746e5SOllivier Robert 	if ((cp = jupiter_send(peer, hp)) != NULL)
1048c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_reqmsg: %u: %s\n", id, cp);
1049c0b746e5SOllivier Robert }
1050c0b746e5SOllivier Robert 
1051c0b746e5SOllivier Robert /* Cancel periodic message output */
1052c0b746e5SOllivier Robert static struct jheader canmsg = {
1053c0b746e5SOllivier Robert 	putshort(JUPITER_SYNC), 0, 0, 0,
1054c0b746e5SOllivier Robert 	putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC),
1055c0b746e5SOllivier Robert 	0
1056c0b746e5SOllivier Robert };
1057c0b746e5SOllivier Robert 
1058c0b746e5SOllivier Robert static void
1059c0b746e5SOllivier Robert jupiter_canmsg(register struct peer *peer, register u_int id)
1060c0b746e5SOllivier Robert {
1061c0b746e5SOllivier Robert 	register struct jheader *hp;
1062c0b746e5SOllivier Robert 	register char *cp;
1063c0b746e5SOllivier Robert 
1064c0b746e5SOllivier Robert 	hp = &canmsg;
1065c0b746e5SOllivier Robert 	hp->id = putshort(id);
1066c0b746e5SOllivier Robert 	if ((cp = jupiter_send(peer, hp)) != NULL)
1067c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_canmsg: %u: %s\n", id, cp);
1068c0b746e5SOllivier Robert }
1069c0b746e5SOllivier Robert 
1070c0b746e5SOllivier Robert /* Request a single message output */
1071c0b746e5SOllivier Robert static struct jheader reqonemsg = {
1072c0b746e5SOllivier Robert 	putshort(JUPITER_SYNC), 0, 0, 0,
1073c0b746e5SOllivier Robert 	putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY),
1074c0b746e5SOllivier Robert 	0
1075c0b746e5SOllivier Robert };
1076c0b746e5SOllivier Robert 
1077c0b746e5SOllivier Robert static void
1078c0b746e5SOllivier Robert jupiter_reqonemsg(register struct peer *peer, register u_int id)
1079c0b746e5SOllivier Robert {
1080c0b746e5SOllivier Robert 	register struct jheader *hp;
1081c0b746e5SOllivier Robert 	register char *cp;
1082c0b746e5SOllivier Robert 
1083c0b746e5SOllivier Robert 	hp = &reqonemsg;
1084c0b746e5SOllivier Robert 	hp->id = putshort(id);
1085c0b746e5SOllivier Robert 	if ((cp = jupiter_send(peer, hp)) != NULL)
1086c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_reqonemsg: %u: %s\n", id, cp);
1087c0b746e5SOllivier Robert }
1088c0b746e5SOllivier Robert 
1089c0b746e5SOllivier Robert /* Set the platform dynamics */
1090c0b746e5SOllivier Robert static struct {
1091c0b746e5SOllivier Robert 	struct jheader jheader;
1092c0b746e5SOllivier Robert 	struct jplat jplat;
1093c0b746e5SOllivier Robert } platmsg = {
1094c0b746e5SOllivier Robert 	{ putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT),
1095c0b746e5SOllivier Robert 	    putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0,
1096c0b746e5SOllivier Robert 	    putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 },
1097c0b746e5SOllivier Robert 	{ 0, 0, 0 }
1098c0b746e5SOllivier Robert };
1099c0b746e5SOllivier Robert 
1100c0b746e5SOllivier Robert static void
1101c0b746e5SOllivier Robert jupiter_platform(register struct peer *peer, register u_int platform)
1102c0b746e5SOllivier Robert {
1103c0b746e5SOllivier Robert 	register struct jheader *hp;
1104c0b746e5SOllivier Robert 	register struct jplat *pp;
1105c0b746e5SOllivier Robert 	register char *cp;
1106c0b746e5SOllivier Robert 
1107c0b746e5SOllivier Robert 	hp = &platmsg.jheader;
1108c0b746e5SOllivier Robert 	pp = &platmsg.jplat;
1109c0b746e5SOllivier Robert 	pp->platform = putshort(platform);
1110c0b746e5SOllivier Robert 	if ((cp = jupiter_send(peer, hp)) != NULL)
1111c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_platform: %u: %s\n", platform, cp);
1112c0b746e5SOllivier Robert }
1113c0b746e5SOllivier Robert 
1114c0b746e5SOllivier Robert /* Checksum "len" shorts */
1115c0b746e5SOllivier Robert static u_short
1116c0b746e5SOllivier Robert jupiter_cksum(register u_short *sp, register u_int len)
1117c0b746e5SOllivier Robert {
1118c0b746e5SOllivier Robert 	register u_short sum, x;
1119c0b746e5SOllivier Robert 
1120c0b746e5SOllivier Robert 	sum = 0;
1121c0b746e5SOllivier Robert 	while (len-- > 0) {
1122c0b746e5SOllivier Robert 		x = *sp++;
1123c0b746e5SOllivier Robert 		sum += getshort(x);
1124c0b746e5SOllivier Robert 	}
1125c0b746e5SOllivier Robert 	return (~sum + 1);
1126c0b746e5SOllivier Robert }
1127c0b746e5SOllivier Robert 
1128c0b746e5SOllivier Robert /* Return the size of the next message (or zero if we don't have it all yet) */
1129c0b746e5SOllivier Robert static int
1130c0b746e5SOllivier Robert jupiter_recv(register struct peer *peer)
1131c0b746e5SOllivier Robert {
1132c0b746e5SOllivier Robert 	register int n, len, size, cc;
1133c0b746e5SOllivier Robert 	register struct refclockproc *pp;
1134c0b746e5SOllivier Robert 	register struct jupiterunit *up;
1135c0b746e5SOllivier Robert 	register struct jheader *hp;
1136c0b746e5SOllivier Robert 	register u_char *bp;
1137c0b746e5SOllivier Robert 	register u_short *sp;
1138c0b746e5SOllivier Robert 
1139c0b746e5SOllivier Robert 	pp = peer->procptr;
1140c0b746e5SOllivier Robert 	up = (struct jupiterunit *)pp->unitptr;
1141c0b746e5SOllivier Robert 
1142c0b746e5SOllivier Robert 	/* Must have at least a header's worth */
1143c0b746e5SOllivier Robert 	cc = sizeof(*hp);
1144c0b746e5SOllivier Robert 	size = up->ssize;
1145c0b746e5SOllivier Robert 	if (size < cc)
1146c0b746e5SOllivier Robert 		return (0);
1147c0b746e5SOllivier Robert 
1148c0b746e5SOllivier Robert 	/* Search for the sync short if missing */
1149c0b746e5SOllivier Robert 	sp = up->sbuf;
1150c0b746e5SOllivier Robert 	hp = (struct jheader *)sp;
1151c0b746e5SOllivier Robert 	if (getshort(hp->sync) != JUPITER_SYNC) {
1152c0b746e5SOllivier Robert 		/* Wasn't at the front, sync up */
1153c0b746e5SOllivier Robert 		jupiter_debug(peer, "syncing");
1154c0b746e5SOllivier Robert 		bp = (u_char *)sp;
1155c0b746e5SOllivier Robert 		n = size;
1156c0b746e5SOllivier Robert 		while (n >= 2) {
1157c0b746e5SOllivier Robert 			if (bp[0] != (JUPITER_SYNC & 0xff)) {
1158c0b746e5SOllivier Robert 				jupiter_debug(peer, "{0x%x}", bp[0]);
1159c0b746e5SOllivier Robert 				++bp;
1160c0b746e5SOllivier Robert 				--n;
1161c0b746e5SOllivier Robert 				continue;
1162c0b746e5SOllivier Robert 			}
1163c0b746e5SOllivier Robert 			if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
1164c0b746e5SOllivier Robert 				break;
1165c0b746e5SOllivier Robert 			jupiter_debug(peer, "{0x%x 0x%x}", bp[0], bp[1]);
1166c0b746e5SOllivier Robert 			bp += 2;
1167c0b746e5SOllivier Robert 			n -= 2;
1168c0b746e5SOllivier Robert 		}
1169c0b746e5SOllivier Robert 		jupiter_debug(peer, "\n");
1170c0b746e5SOllivier Robert 		/* Shuffle data to front of input buffer */
1171c0b746e5SOllivier Robert 		if (n > 0)
1172c0b746e5SOllivier Robert 			memcpy(sp, bp, n);
1173c0b746e5SOllivier Robert 		size = n;
1174c0b746e5SOllivier Robert 		up->ssize = size;
1175c0b746e5SOllivier Robert 		if (size < cc || hp->sync != JUPITER_SYNC)
1176c0b746e5SOllivier Robert 			return (0);
1177c0b746e5SOllivier Robert 	}
1178c0b746e5SOllivier Robert 
1179c0b746e5SOllivier Robert 	if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
1180c0b746e5SOllivier Robert 	    getshort(hp->hsum)) {
1181c0b746e5SOllivier Robert 	    jupiter_debug(peer, "jupiter_recv: bad header checksum!\n");
1182c0b746e5SOllivier Robert 		/* This is drastic but checksum errors should be rare */
1183c0b746e5SOllivier Robert 		up->ssize = 0;
1184c0b746e5SOllivier Robert 		return (0);
1185c0b746e5SOllivier Robert 	}
1186c0b746e5SOllivier Robert 
1187c0b746e5SOllivier Robert 	/* Check for a payload */
1188c0b746e5SOllivier Robert 	len = getshort(hp->len);
1189c0b746e5SOllivier Robert 	if (len > 0) {
1190c0b746e5SOllivier Robert 		n = (len + 1) * sizeof(u_short);
1191c0b746e5SOllivier Robert 		/* Not enough data yet */
1192c0b746e5SOllivier Robert 		if (size < cc + n)
1193c0b746e5SOllivier Robert 			return (0);
1194c0b746e5SOllivier Robert 
1195c0b746e5SOllivier Robert 		/* Check payload checksum */
1196c0b746e5SOllivier Robert 		sp = (u_short *)(hp + 1);
1197c0b746e5SOllivier Robert 		if (jupiter_cksum(sp, len) != getshort(sp[len])) {
1198c0b746e5SOllivier Robert 			jupiter_debug(peer,
1199c0b746e5SOllivier Robert 			    "jupiter_recv: bad payload checksum!\n");
1200c0b746e5SOllivier Robert 			/* This is drastic but checksum errors should be rare */
1201c0b746e5SOllivier Robert 			up->ssize = 0;
1202c0b746e5SOllivier Robert 			return (0);
1203c0b746e5SOllivier Robert 		}
1204c0b746e5SOllivier Robert 		cc += n;
1205c0b746e5SOllivier Robert 	}
1206c0b746e5SOllivier Robert 	return (cc);
1207c0b746e5SOllivier Robert }
1208c0b746e5SOllivier Robert 
1209c0b746e5SOllivier Robert static int
1210c0b746e5SOllivier Robert jupiter_ttyinit(register struct peer *peer, register int fd)
1211c0b746e5SOllivier Robert {
1212c0b746e5SOllivier Robert 	struct termios termios;
1213c0b746e5SOllivier Robert 
1214c0b746e5SOllivier Robert 	memset((char *)&termios, 0, sizeof(termios));
1215c0b746e5SOllivier Robert 	if (cfsetispeed(&termios, B9600) < 0 ||
1216c0b746e5SOllivier Robert 	    cfsetospeed(&termios, B9600) < 0) {
1217c0b746e5SOllivier Robert 		jupiter_debug(peer,
1218c0b746e5SOllivier Robert 		    "jupiter_ttyinit: cfsetispeed/cfgetospeed: %s\n",
1219c0b746e5SOllivier Robert 		    strerror(errno));
1220c0b746e5SOllivier Robert 		return (0);
1221c0b746e5SOllivier Robert 	}
1222c0b746e5SOllivier Robert #ifdef HAVE_CFMAKERAW
1223c0b746e5SOllivier Robert 	cfmakeraw(&termios);
1224c0b746e5SOllivier Robert #else
1225c0b746e5SOllivier Robert 	termios.c_iflag &= ~(IMAXBEL | IXOFF | INPCK | BRKINT | PARMRK |
1226c0b746e5SOllivier Robert 	    ISTRIP | INLCR | IGNCR | ICRNL | IXON | IGNPAR);
1227c0b746e5SOllivier Robert 	termios.c_iflag |= IGNBRK;
1228c0b746e5SOllivier Robert 	termios.c_oflag &= ~OPOST;
1229c0b746e5SOllivier Robert 	termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG |
1230c0b746e5SOllivier Robert 	    IEXTEN | NOFLSH | TOSTOP | PENDIN);
1231c0b746e5SOllivier Robert 	termios.c_cflag &= ~(CSIZE | PARENB);
1232c0b746e5SOllivier Robert 	termios.c_cflag |= CS8 | CREAD;
1233c0b746e5SOllivier Robert 	termios.c_cc[VMIN] = 1;
1234c0b746e5SOllivier Robert #endif
1235c0b746e5SOllivier Robert 	termios.c_cflag |= CLOCAL;
1236c0b746e5SOllivier Robert 	if (tcsetattr(fd, TCSANOW, &termios) < 0) {
1237c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_ttyinit: tcsetattr: %s\n",
1238c0b746e5SOllivier Robert 		    strerror(errno));
1239c0b746e5SOllivier Robert 		return (0);
1240c0b746e5SOllivier Robert 	}
1241c0b746e5SOllivier Robert 
1242c0b746e5SOllivier Robert #ifdef TIOCSPPS
1243c0b746e5SOllivier Robert 	if (ioctl(fd, TIOCSPPS, (char *)&fdpps) < 0) {
1244c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_ttyinit: TIOCSPPS: %s\n",
1245c0b746e5SOllivier Robert 		    strerror(errno));
1246c0b746e5SOllivier Robert 		return (0);
1247c0b746e5SOllivier Robert 	}
1248c0b746e5SOllivier Robert #endif
1249c0b746e5SOllivier Robert #ifdef I_PUSH
1250c0b746e5SOllivier Robert 	if (ioctl(fd, I_PUSH, "ppsclock") < 0) {
1251c0b746e5SOllivier Robert 		jupiter_debug(peer, "jupiter_ttyinit: push ppsclock: %s\n",
1252c0b746e5SOllivier Robert 		    strerror(errno));
1253c0b746e5SOllivier Robert 		return (0);
1254c0b746e5SOllivier Robert 	}
1255c0b746e5SOllivier Robert #endif
1256c0b746e5SOllivier Robert 
1257c0b746e5SOllivier Robert 	return (1);
1258c0b746e5SOllivier Robert }
1259c0b746e5SOllivier Robert 
1260c0b746e5SOllivier Robert #else /* not (REFCLOCK && CLOCK_JUPITER && PPS) */
1261c0b746e5SOllivier Robert int refclock_jupiter_bs;
1262c0b746e5SOllivier Robert #endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */
1263