xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_jupiter.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: refclock_jupiter.c,v 1.11 2016/11/22 03:09:30 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997, 1998, 2003
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Lawrence Berkeley Laboratory.
19  * 4. The name of the University may not be used to endorse or promote
20  *    products derived from this software without specific prior
21  *    written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39 
40 #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI)
41 
42 #include "ntpd.h"
43 #include "ntp_io.h"
44 #include "ntp_refclock.h"
45 #include "ntp_unixtime.h"
46 #include "ntp_stdlib.h"
47 
48 #include <stdio.h>
49 #include <ctype.h>
50 
51 #include "jupiter.h"
52 
53 #ifdef HAVE_PPSAPI
54 # include "ppsapi_timepps.h"
55 #endif
56 
57 #ifdef WORDS_BIGENDIAN
58 #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
59 #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
60 #else
61 #define getshort(s) ((u_short)(s))
62 #define putshort(s) ((u_short)(s))
63 #endif
64 
65 /*
66  * This driver supports the Rockwell Jupiter GPS Receiver board
67  * adapted to precision timing applications.  It requires the
68  * ppsclock line discipline or streams module described in the
69  * Line Disciplines and Streams Drivers page. It also requires a
70  * gadget box and 1-PPS level converter, such as described in the
71  * Pulse-per-second (PPS) Signal Interfacing page.
72  *
73  * It may work (with minor modifications) with other Rockwell GPS
74  * receivers such as the CityTracker.
75  */
76 
77 /*
78  * GPS Definitions
79  */
80 #define	DEVICE		"/dev/gps%d"	/* device name and unit */
81 #define	SPEED232	B9600		/* baud */
82 
83 /*
84  * Radio interface parameters
85  */
86 #define	PRECISION	(-18)	/* precision assumed (about 4 us) */
87 #define	REFID	"GPS\0"		/* reference id */
88 #define	DESCRIPTION	"Rockwell Jupiter GPS Receiver" /* who we are */
89 #define	DEFFUDGETIME	0	/* default fudge time (ms) */
90 
91 /* Unix timestamp for the GPS epoch: January 6, 1980 */
92 #define GPS_EPOCH 315964800
93 
94 /* Rata Die Number of first day of GPS epoch. This is the number of days
95  * since 0000-12-31 to 1980-01-06 in the proleptic Gregorian Calendar.
96  */
97 #define RDN_GPS_EPOCH (4*146097 + 138431 + 1)
98 
99 /* Double short to unsigned int */
100 #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
101 
102 /* Double short to signed int */
103 #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
104 
105 /* One week's worth of seconds */
106 #define WEEKSECS (7 * 24 * 60 * 60)
107 
108 /*
109  * Jupiter unit control structure.
110  */
111 struct instance {
112 	struct peer *peer;		/* peer */
113 	u_int  pollcnt;			/* poll message counter */
114 	u_int  polled;			/* Hand in a time sample? */
115 #ifdef HAVE_PPSAPI
116 	pps_params_t pps_params;	/* pps parameters */
117 	pps_info_t pps_info;		/* last pps data */
118 	pps_handle_t pps_handle;	/* pps handle */
119 	u_int assert;			/* pps edge to use */
120 	u_int hardpps;			/* enable kernel mode */
121 	struct timespec ts;		/* last timestamp */
122 #endif
123 	l_fp limit;
124 	u_int gpos_gweek;		/* Current GPOS GPS week number */
125 	u_int gpos_sweek;		/* Current GPOS GPS seconds into week */
126 	u_int gweek;			/* current GPS week number */
127 	u_int32 lastsweek;		/* last seconds into GPS week */
128 	time_t timecode;		/* current ntp timecode */
129 	u_int32 stime;			/* used to detect firmware bug */
130 	int wantid;			/* don't reconfig on channel id msg */
131 	u_int  moving;			/* mobile platform? */
132 	u_char sloppyclockflag;		/* fudge flags */
133 	u_short sbuf[512];		/* local input buffer */
134 	int ssize;			/* space used in sbuf */
135 };
136 
137 /*
138  * Function prototypes
139  */
140 static	void	jupiter_canmsg	(struct instance *, u_int);
141 static	u_short	jupiter_cksum	(u_short *, u_int);
142 static	int	jupiter_config	(struct instance *);
143 static	void	jupiter_debug	(struct peer *, const char *,
144 				 const char *, ...) NTP_SYSLOG(3, 4);
145 static	const char *	jupiter_parse_t	(struct instance *, u_short *);
146 static	const char *	jupiter_parse_gpos	(struct instance *, u_short *);
147 static	void	jupiter_platform	(struct instance *, u_int);
148 static	void	jupiter_poll	(int, struct peer *);
149 static	void	jupiter_control	(int, const struct refclockstat *,
150 				 struct refclockstat *, struct peer *);
151 #ifdef HAVE_PPSAPI
152 static	int	jupiter_ppsapi	(struct instance *);
153 static	int	jupiter_pps	(struct instance *);
154 #endif /* HAVE_PPSAPI */
155 static	int	jupiter_recv	(struct instance *);
156 static	void	jupiter_receive (struct recvbuf *rbufp);
157 static	void	jupiter_reqmsg	(struct instance *, u_int, u_int);
158 static	void	jupiter_reqonemsg(struct instance *, u_int);
159 static	char *	jupiter_send	(struct instance *, struct jheader *);
160 static	void	jupiter_shutdown(int, struct peer *);
161 static	int	jupiter_start	(int, struct peer *);
162 
163 static	u_int	get_full_week(u_int base_week, u_int gpos_week);
164 static	u_int	get_base_week(void);
165 
166 
167 /*
168  * Transfer vector
169  */
170 struct	refclock refclock_jupiter = {
171 	jupiter_start,		/* start up driver */
172 	jupiter_shutdown,	/* shut down driver */
173 	jupiter_poll,		/* transmit poll message */
174 	jupiter_control,	/* (clock control) */
175 	noentry,		/* (clock init) */
176 	noentry,		/* (clock buginfo) */
177 	NOFLAGS			/* not used */
178 };
179 
180 /*
181  * jupiter_start - open the devices and initialize data for processing
182  */
183 static int
184 jupiter_start(
185 	int unit,
186 	struct peer *peer
187 	)
188 {
189 	struct refclockproc *pp;
190 	struct instance *instance;
191 	int fd;
192 	char gpsdev[20];
193 
194 	/*
195 	 * Open serial port
196 	 */
197 	snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
198 	fd = refclock_open(gpsdev, SPEED232, LDISC_RAW);
199 	if (fd <= 0) {
200 		jupiter_debug(peer, "jupiter_start", "open %s: %m",
201 			      gpsdev);
202 		return (0);
203 	}
204 
205 	/* Allocate unit structure */
206 	instance = emalloc_zero(sizeof(*instance));
207 	instance->peer = peer;
208 	pp = peer->procptr;
209 	pp->io.clock_recv = jupiter_receive;
210 	pp->io.srcclock = peer;
211 	pp->io.datalen = 0;
212 	pp->io.fd = fd;
213 	if (!io_addclock(&pp->io)) {
214 		close(fd);
215 		pp->io.fd = -1;
216 		free(instance);
217 		return (0);
218 	}
219 	pp->unitptr = instance;
220 
221 	/*
222 	 * Initialize miscellaneous variables
223 	 */
224 	peer->precision = PRECISION;
225 	pp->clockdesc = DESCRIPTION;
226 	memcpy((char *)&pp->refid, REFID, 4);
227 
228 #ifdef HAVE_PPSAPI
229 	instance->assert = 1;
230 	instance->hardpps = 0;
231 	/*
232 	 * Start the PPSAPI interface if it is there. Default to use
233 	 * the assert edge and do not enable the kernel hardpps.
234 	 */
235 	if (time_pps_create(fd, &instance->pps_handle) < 0) {
236 		instance->pps_handle = 0;
237 		msyslog(LOG_ERR,
238 			"refclock_jupiter: time_pps_create failed: %m");
239 	}
240 	else if (!jupiter_ppsapi(instance))
241 		goto clean_up;
242 #endif /* HAVE_PPSAPI */
243 
244 	/* Ensure the receiver is properly configured */
245 	if (!jupiter_config(instance))
246 		goto clean_up;
247 
248 	return (1);
249 
250 clean_up:
251 	jupiter_shutdown(unit, peer);
252 	pp->unitptr = 0;
253 	return (0);
254 }
255 
256 /*
257  * jupiter_shutdown - shut down the clock
258  */
259 static void
260 jupiter_shutdown(int unit, struct peer *peer)
261 {
262 	struct instance *instance;
263 	struct refclockproc *pp;
264 
265 	pp = peer->procptr;
266 	instance = pp->unitptr;
267 	if (!instance)
268 		return;
269 
270 #ifdef HAVE_PPSAPI
271 	if (instance->pps_handle) {
272 		time_pps_destroy(instance->pps_handle);
273 		instance->pps_handle = 0;
274 	}
275 #endif /* HAVE_PPSAPI */
276 
277 	if (pp->io.fd != -1)
278 		io_closeclock(&pp->io);
279 	free(instance);
280 }
281 
282 /*
283  * jupiter_config - Configure the receiver
284  */
285 static int
286 jupiter_config(struct instance *instance)
287 {
288 	jupiter_debug(instance->peer, __func__, "init receiver");
289 
290 	/*
291 	 * Initialize the unit variables
292 	 */
293 	instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag;
294 	instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2);
295 	if (instance->moving)
296 		jupiter_debug(instance->peer, __func__, "mobile platform");
297 
298 	instance->pollcnt     = 2;
299 	instance->polled      = 0;
300 	instance->gpos_gweek = 0;
301 	instance->gpos_sweek = 0;
302 	instance->gweek = 0;
303 	instance->lastsweek = 2 * WEEKSECS;
304 	instance->timecode = 0;
305 	instance->stime = 0;
306 	instance->ssize = 0;
307 
308 	/* Stop outputting all messages */
309 	jupiter_canmsg(instance, JUPITER_ALL);
310 
311 	/* Request the receiver id so we can syslog the firmware version */
312 	jupiter_reqonemsg(instance, JUPITER_O_ID);
313 
314 	/* Flag that this the id was requested (so we don't get called again) */
315 	instance->wantid = 1;
316 
317 	/* Request perodic time mark pulse messages */
318 	jupiter_reqmsg(instance, JUPITER_O_PULSE, 1);
319 
320 	/* Request perodic geodetic position status */
321 	jupiter_reqmsg(instance, JUPITER_O_GPOS, 1);
322 
323 	/* Set application platform type */
324 	if (instance->moving)
325 		jupiter_platform(instance, JUPITER_I_PLAT_MED);
326 	else
327 		jupiter_platform(instance, JUPITER_I_PLAT_LOW);
328 
329 	return (1);
330 }
331 
332 #ifdef HAVE_PPSAPI
333 /*
334  * Initialize PPSAPI
335  */
336 int
337 jupiter_ppsapi(
338 	struct instance *instance	/* unit structure pointer */
339 	)
340 {
341 	int capability;
342 
343 	if (time_pps_getcap(instance->pps_handle, &capability) < 0) {
344 		msyslog(LOG_ERR,
345 		    "refclock_jupiter: time_pps_getcap failed: %m");
346 		return (0);
347 	}
348 	memset(&instance->pps_params, 0, sizeof(pps_params_t));
349 	if (!instance->assert)
350 		instance->pps_params.mode = capability & PPS_CAPTURECLEAR;
351 	else
352 		instance->pps_params.mode = capability & PPS_CAPTUREASSERT;
353 	if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
354 		msyslog(LOG_ERR,
355 		    "refclock_jupiter: invalid capture edge %d",
356 		    instance->assert);
357 		return (0);
358 	}
359 	instance->pps_params.mode |= PPS_TSFMT_TSPEC;
360 	if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) {
361 		msyslog(LOG_ERR,
362 		    "refclock_jupiter: time_pps_setparams failed: %m");
363 		return (0);
364 	}
365 	if (instance->hardpps) {
366 		if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS,
367 				    instance->pps_params.mode & ~PPS_TSFMT_TSPEC,
368 				    PPS_TSFMT_TSPEC) < 0) {
369 			msyslog(LOG_ERR,
370 			    "refclock_jupiter: time_pps_kcbind failed: %m");
371 			return (0);
372 		}
373 		hardpps_enable = 1;
374 	}
375 /*	instance->peer->precision = PPS_PRECISION; */
376 
377 #if DEBUG
378 	if (debug) {
379 		time_pps_getparams(instance->pps_handle, &instance->pps_params);
380 		jupiter_debug(instance->peer, __func__,
381 			"pps capability 0x%x version %d mode 0x%x kern %d",
382 			capability, instance->pps_params.api_version,
383 			instance->pps_params.mode, instance->hardpps);
384 	}
385 #endif
386 
387 	return (1);
388 }
389 
390 /*
391  * Get PPSAPI timestamps.
392  *
393  * Return 0 on failure and 1 on success.
394  */
395 static int
396 jupiter_pps(struct instance *instance)
397 {
398 	pps_info_t pps_info;
399 	struct timespec timeout, ts;
400 	double dtemp;
401 	l_fp tstmp;
402 
403 	/*
404 	 * Convert the timespec nanoseconds field to ntp l_fp units.
405 	 */
406 	if (instance->pps_handle == 0)
407 		return 1;
408 	timeout.tv_sec = 0;
409 	timeout.tv_nsec = 0;
410 	memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t));
411 	if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info,
412 	    &timeout) < 0)
413 		return 1;
414 	if (instance->pps_params.mode & PPS_CAPTUREASSERT) {
415 		if (pps_info.assert_sequence ==
416 		    instance->pps_info.assert_sequence)
417 			return 1;
418 		ts = instance->pps_info.assert_timestamp;
419 	} else if (instance->pps_params.mode & PPS_CAPTURECLEAR) {
420 		if (pps_info.clear_sequence ==
421 		    instance->pps_info.clear_sequence)
422 			return 1;
423 		ts = instance->pps_info.clear_timestamp;
424 	} else {
425 		return 1;
426 	}
427 	if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec))
428 		return 1;
429 	instance->ts = ts;
430 
431 	tstmp.l_ui = (u_int32)ts.tv_sec + JAN_1970;
432 	dtemp = ts.tv_nsec * FRAC / 1e9;
433 	tstmp.l_uf = (u_int32)dtemp;
434 	instance->peer->procptr->lastrec = tstmp;
435 	return 0;
436 }
437 #endif /* HAVE_PPSAPI */
438 
439 /*
440  * jupiter_poll - jupiter watchdog routine
441  */
442 static void
443 jupiter_poll(int unit, struct peer *peer)
444 {
445 	struct instance *instance;
446 	struct refclockproc *pp;
447 
448 	pp = peer->procptr;
449 	instance = pp->unitptr;
450 
451 	/*
452 	 * You don't need to poll this clock.  It puts out timecodes
453 	 * once per second.  If asked for a timestamp, take note.
454 	 * The next time a timecode comes in, it will be fed back.
455 	 */
456 
457 	/*
458 	 * If we haven't had a response in a while, reset the receiver.
459 	 */
460 	if (instance->pollcnt > 0) {
461 		instance->pollcnt--;
462 	} else {
463 		refclock_report(peer, CEVNT_TIMEOUT);
464 
465 		/* Request the receiver id to trigger a reconfig */
466 		jupiter_reqonemsg(instance, JUPITER_O_ID);
467 		instance->wantid = 0;
468 	}
469 
470 	/*
471 	 * polled every 64 seconds. Ask jupiter_receive to hand in
472 	 * a timestamp.
473 	 */
474 	instance->polled = 1;
475 	pp->polls++;
476 }
477 
478 /*
479  * jupiter_control - fudge control
480  */
481 static void
482 jupiter_control(
483 	int unit,		/* unit (not used) */
484 	const struct refclockstat *in, /* input parameters (not used) */
485 	struct refclockstat *out, /* output parameters (not used) */
486 	struct peer *peer	/* peer structure pointer */
487 	)
488 {
489 	struct refclockproc *pp;
490 	struct instance *instance;
491 	u_char sloppyclockflag;
492 
493 	pp = peer->procptr;
494 	instance = pp->unitptr;
495 
496 	DTOLFP(pp->fudgetime2, &instance->limit);
497 	/* Force positive value. */
498 	if (L_ISNEG(&instance->limit))
499 		L_NEG(&instance->limit);
500 
501 #ifdef HAVE_PPSAPI
502 	instance->assert = !(pp->sloppyclockflag & CLK_FLAG3);
503 	jupiter_ppsapi(instance);
504 #endif /* HAVE_PPSAPI */
505 
506 	sloppyclockflag = instance->sloppyclockflag;
507 	instance->sloppyclockflag = pp->sloppyclockflag;
508 	if ((instance->sloppyclockflag & CLK_FLAG2) !=
509 	    (sloppyclockflag & CLK_FLAG2)) {
510 		jupiter_debug(peer, __func__,
511 		    "mode switch: reset receiver");
512 		jupiter_config(instance);
513 		return;
514 	}
515 }
516 
517 /*
518  * jupiter_receive - receive gps data
519  * Gag me!
520  */
521 static void
522 jupiter_receive(struct recvbuf *rbufp)
523 {
524 	size_t bpcnt;
525 	int cc, size, ppsret;
526 	time_t last_timecode;
527 	u_int32 laststime;
528 	const char *cp;
529 	u_char *bp;
530 	u_short *sp;
531 	struct jid *ip;
532 	struct jheader *hp;
533 	struct peer *peer;
534 	struct refclockproc *pp;
535 	struct instance *instance;
536 	l_fp tstamp;
537 
538 	/* Initialize pointers and read the timecode and timestamp */
539 	peer = rbufp->recv_peer;
540 	pp = peer->procptr;
541 	instance = pp->unitptr;
542 
543 	bp = (u_char *)rbufp->recv_buffer;
544 	bpcnt = rbufp->recv_length;
545 
546 	/* This shouldn't happen */
547 	if (bpcnt > sizeof(instance->sbuf) - instance->ssize)
548 		bpcnt = sizeof(instance->sbuf) - instance->ssize;
549 
550 	/* Append to input buffer */
551 	memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt);
552 	instance->ssize += bpcnt;
553 
554 	/* While there's at least a header and we parse an intact message */
555 	while (instance->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) {
556 		instance->pollcnt = 2;
557 
558 		tstamp = rbufp->recv_time;
559 		hp = (struct jheader *)instance->sbuf;
560 		sp = (u_short *)(hp + 1);
561 		size = cc - sizeof(*hp);
562 		switch (getshort(hp->id)) {
563 
564 		case JUPITER_O_PULSE:
565 			if (size != sizeof(struct jpulse)) {
566 				jupiter_debug(peer, __func__,
567 				    "pulse: len %d != %u",
568 				    size, (int)sizeof(struct jpulse));
569 				refclock_report(peer, CEVNT_BADREPLY);
570 				break;
571 			}
572 
573 			/*
574 			 * There appears to be a firmware bug related
575 			 * to the pulse message; in addition to the one
576 			 * per second messages, we get an extra pulse
577 			 * message once an hour (on the anniversary of
578 			 * the cold start). It seems to come 200 ms
579 			 * after the one requested. So if we've seen a
580 			 * pulse message in the last 210 ms, we skip
581 			 * this one.
582 			 */
583 			laststime = instance->stime;
584 			instance->stime = DS2UI(((struct jpulse *)sp)->stime);
585 			if (laststime != 0 && instance->stime - laststime <= 21) {
586 				jupiter_debug(peer, __func__,
587 				"avoided firmware bug (stime %.2f, laststime %.2f)",
588 				(double)instance->stime * 0.01, (double)laststime * 0.01);
589 				break;
590 			}
591 
592 			/* Retrieve pps timestamp */
593 			ppsret = jupiter_pps(instance);
594 
595 			/*
596 			 * Add one second if msg received early
597 			 * (i.e. before limit, a.k.a. fudgetime2) in
598 			 * the second.
599 			 */
600 			L_SUB(&tstamp, &pp->lastrec);
601 			if (!L_ISGEQ(&tstamp, &instance->limit))
602 				++pp->lastrec.l_ui;
603 
604 			/* Parse timecode (even when there's no pps) */
605 			last_timecode = instance->timecode;
606 			if ((cp = jupiter_parse_t(instance, sp)) != NULL) {
607 				jupiter_debug(peer, __func__,
608 				    "pulse: %s", cp);
609 				break;
610 			}
611 
612 			/* Bail if we didn't get a pps timestamp */
613 			if (ppsret)
614 				break;
615 
616 			/* Bail if we don't have the last timecode yet */
617 			if (last_timecode == 0)
618 				break;
619 
620 			/* Add the new sample to a median filter */
621 			tstamp.l_ui = JAN_1970 + (u_int32)last_timecode;
622 			tstamp.l_uf = 0;
623 
624 			refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1);
625 
626 			/*
627 			 * The clock will blurt a timecode every second
628 			 * but we only want one when polled.  If we
629 			 * havn't been polled, bail out.
630 			 */
631 			if (!instance->polled)
632 				break;
633 			instance->polled = 0;
634 
635 			/*
636 			 * It's a live one!  Remember this time.
637 			 */
638 
639 			pp->lastref = pp->lastrec;
640 			refclock_receive(peer);
641 
642 			/*
643 			 * If we get here - what we got from the clock is
644 			 * OK, so say so
645 			 */
646 			refclock_report(peer, CEVNT_NOMINAL);
647 
648 			/*
649 			 * We have succeeded in answering the poll.
650 			 * Turn off the flag and return
651 			 */
652 			instance->polled = 0;
653 			break;
654 
655 		case JUPITER_O_GPOS:
656 			if (size != sizeof(struct jgpos)) {
657 				jupiter_debug(peer, __func__,
658 				    "gpos: len %d != %u",
659 				    size, (int)sizeof(struct jgpos));
660 				refclock_report(peer, CEVNT_BADREPLY);
661 				break;
662 			}
663 
664 			if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) {
665 				jupiter_debug(peer, __func__,
666 				    "gpos: %s", cp);
667 				break;
668 			}
669 			break;
670 
671 		case JUPITER_O_ID:
672 			if (size != sizeof(struct jid)) {
673 				jupiter_debug(peer, __func__,
674 				    "id: len %d != %u",
675 				    size, (int)sizeof(struct jid));
676 				refclock_report(peer, CEVNT_BADREPLY);
677 				break;
678 			}
679 			/*
680 			 * If we got this message because the Jupiter
681 			 * just powered instance, it needs to be reconfigured.
682 			 */
683 			ip = (struct jid *)sp;
684 			jupiter_debug(peer, __func__,
685 			    "%s chan ver %s, %s (%s)",
686 			    ip->chans, ip->vers, ip->date, ip->opts);
687 			msyslog(LOG_DEBUG,
688 			    "jupiter_receive: %s chan ver %s, %s (%s)",
689 			    ip->chans, ip->vers, ip->date, ip->opts);
690 			if (instance->wantid)
691 				instance->wantid = 0;
692 			else {
693 				jupiter_debug(peer, __func__, "reset receiver");
694 				jupiter_config(instance);
695 				/*
696 				 * Restore since jupiter_config() just
697 				 * zeroed it
698 				 */
699 				instance->ssize = cc;
700 			}
701 			break;
702 
703 		default:
704 			jupiter_debug(peer, __func__, "unknown message id %d",
705 			    getshort(hp->id));
706 			break;
707 		}
708 		instance->ssize -= cc;
709 		if (instance->ssize < 0) {
710 			fprintf(stderr, "jupiter_recv: negative ssize!\n");
711 			abort();
712 		} else if (instance->ssize > 0)
713 			memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize);
714 	}
715 }
716 
717 static const char *
718 jupiter_parse_t(struct instance *instance, u_short *sp)
719 {
720 	struct tm *tm;
721 	char *cp;
722 	struct jpulse *jp;
723 	u_int32 sweek;
724 	time_t last_timecode;
725 	u_short flags;
726 
727 	jp = (struct jpulse *)sp;
728 
729 	/* The timecode is presented as seconds into the current GPS week */
730 	sweek = DS2UI(jp->sweek) % WEEKSECS;
731 
732 	/*
733 	 * If we don't know the current GPS week, calculate it from the
734 	 * current time. (It's too bad they didn't include this
735 	 * important value in the pulse message). We'd like to pick it
736 	 * up from one of the other messages like gpos or chan but they
737 	 * don't appear to be synchronous with time keeping and changes
738 	 * too soon (something like 10 seconds before the new GPS
739 	 * week).
740 	 *
741 	 * If we already know the current GPS week, increment it when
742 	 * we wrap into a new week.
743 	 */
744 	if (instance->gweek == 0) {
745 		if (!instance->gpos_gweek) {
746 			return ("jupiter_parse_t: Unknown gweek");
747 		}
748 
749 		instance->gweek = instance->gpos_gweek;
750 
751 		/*
752 		 * Fix warps. GPOS has GPS time and PULSE has UTC.
753 		 * Plus, GPOS need not be completely in synch with
754 		 * the PPS signal.
755 		 */
756 		if (instance->gpos_sweek >= sweek) {
757 			if ((instance->gpos_sweek - sweek) > WEEKSECS / 2)
758 				++instance->gweek;
759 		}
760 		else {
761 			if ((sweek - instance->gpos_sweek) > WEEKSECS / 2)
762 				--instance->gweek;
763 		}
764 	}
765 	else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) {
766 		++instance->gweek;
767 		jupiter_debug(instance->peer, __func__,
768 		    "NEW gps week %u", instance->gweek);
769 	}
770 
771 	/*
772 	 * See if the sweek stayed the same (this happens when there is
773 	 * no pps pulse).
774 	 *
775 	 * Otherwise, look for time warps:
776 	 *
777 	 *   - we have stored at least one lastsweek and
778 	 *   - the sweek didn't increase by one and
779 	 *   - we didn't wrap to a new GPS week
780 	 *
781 	 * Then we warped.
782 	 */
783 	if (instance->lastsweek == sweek)
784 		jupiter_debug(instance->peer, __func__,
785 		    "gps sweek not incrementing (%d)",
786 		    sweek);
787 	else if (instance->lastsweek != 2 * WEEKSECS &&
788 	    instance->lastsweek + 1 != sweek &&
789 	    !(sweek == 0 && instance->lastsweek == WEEKSECS - 1))
790 		jupiter_debug(instance->peer, __func__,
791 		    "gps sweek jumped (was %d, now %d)",
792 		    instance->lastsweek, sweek);
793 	instance->lastsweek = sweek;
794 
795 	/* This timecode describes next pulse */
796 	last_timecode = instance->timecode;
797 	instance->timecode =
798 	    GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek;
799 
800 	if (last_timecode == 0)
801 		/* XXX debugging */
802 		jupiter_debug(instance->peer, __func__,
803 		    "UTC <none> (gweek/sweek %u/%u)",
804 		    instance->gweek, sweek);
805 	else {
806 		/* XXX debugging */
807 		tm = gmtime(&last_timecode);
808 		cp = asctime(tm);
809 
810 		jupiter_debug(instance->peer, __func__,
811 		    "UTC %.24s (gweek/sweek %u/%u)",
812 		    cp, instance->gweek, sweek);
813 
814 		/* Billboard last_timecode (which is now the current time) */
815 		instance->peer->procptr->year   = tm->tm_year + 1900;
816 		instance->peer->procptr->day    = tm->tm_yday + 1;
817 		instance->peer->procptr->hour   = tm->tm_hour;
818 		instance->peer->procptr->minute = tm->tm_min;
819 		instance->peer->procptr->second = tm->tm_sec;
820 	}
821 
822 	flags = getshort(jp->flags);
823 
824 	/* Toss if not designated "valid" by the gps */
825 	if ((flags & JUPITER_O_PULSE_VALID) == 0) {
826 		refclock_report(instance->peer, CEVNT_BADTIME);
827 		return ("time mark not valid");
828 	}
829 
830 	/* We better be sync'ed to UTC... */
831 	if ((flags & JUPITER_O_PULSE_UTC) == 0) {
832 		refclock_report(instance->peer, CEVNT_BADTIME);
833 		return ("time mark not sync'ed to UTC");
834 	}
835 
836 	return (NULL);
837 }
838 
839 static const char *
840 jupiter_parse_gpos(struct instance *instance, u_short *sp)
841 {
842 	struct jgpos *jg;
843 	time_t t;
844 	struct tm *tm;
845 	char *cp;
846 
847 	jg = (struct jgpos *)sp;
848 
849 	if (jg->navval != 0) {
850 		/*
851 		 * Solution not valid. Use caution and refuse
852 		 * to determine GPS week from this message.
853 		 */
854 		instance->gpos_gweek = 0;
855 		instance->gpos_sweek = 0;
856 		return ("Navigation solution not valid");
857 	}
858 
859 	instance->gpos_sweek = DS2UI(jg->sweek);
860 	instance->gpos_gweek = get_full_week(get_base_week(),
861 					     getshort(jg->gweek));
862 
863 	/* according to the protocol spec, the seconds-in-week cannot
864 	 * exceed the nominal value: Is it really necessary to normalise
865 	 * the seconds???
866 	 */
867 	while(instance->gpos_sweek >= WEEKSECS) {
868 		instance->gpos_sweek -= WEEKSECS;
869 		++instance->gpos_gweek;
870 	}
871 	instance->gweek = 0;
872 
873 	t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek;
874 	tm = gmtime(&t);
875 	cp = asctime(tm);
876 
877 	jupiter_debug(instance->peer, __func__,
878 		"GPS %.24s (gweek/sweek %u/%u)",
879 		cp, instance->gpos_gweek, instance->gpos_sweek);
880 	return (NULL);
881 }
882 
883 /*
884  * jupiter_debug - print debug messages
885  */
886 static void
887 jupiter_debug(
888 	struct peer *	peer,
889 	const char *	function,
890 	const char *	fmt,
891 	...
892 	)
893 {
894 	char	buffer[200];
895 	va_list	ap;
896 
897 	va_start(ap, fmt);
898 	/*
899 	 * Print debug message to stdout
900 	 * In the future, we may want to get get more creative...
901 	 */
902 	mvsnprintf(buffer, sizeof(buffer), fmt, ap);
903 	record_clock_stats(&peer->srcadr, buffer);
904 #ifdef DEBUG
905 	if (debug) {
906 		printf("%s: %s\n", function, buffer);
907 		fflush(stdout);
908 	}
909 #endif
910 
911 	va_end(ap);
912 }
913 
914 /* Checksum and transmit a message to the Jupiter */
915 static char *
916 jupiter_send(struct instance *instance, struct jheader *hp)
917 {
918 	u_int len, size;
919 	ssize_t cc;
920 	u_short *sp;
921 	static char errstr[132];
922 
923 	size = sizeof(*hp);
924 	hp->hsum = putshort(jupiter_cksum((u_short *)hp,
925 	    (size / sizeof(u_short)) - 1));
926 	len = getshort(hp->len);
927 	if (len > 0) {
928 		sp = (u_short *)(hp + 1);
929 		sp[len] = putshort(jupiter_cksum(sp, len));
930 		size += (len + 1) * sizeof(u_short);
931 	}
932 
933 	if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) {
934 		msnprintf(errstr, sizeof(errstr), "write: %m");
935 		return (errstr);
936 	} else if (cc != (int)size) {
937 		snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size);
938 		return (errstr);
939 	}
940 	return (NULL);
941 }
942 
943 /* Request periodic message output */
944 static struct {
945 	struct jheader jheader;
946 	struct jrequest jrequest;
947 } reqmsg = {
948 	{ putshort(JUPITER_SYNC), 0,
949 	    putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1),
950 	    0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK |
951 	    JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 },
952 	{ 0, 0, 0, 0 }
953 };
954 
955 /* An interval of zero means to output on trigger */
956 static void
957 jupiter_reqmsg(struct instance *instance, u_int id,
958     u_int interval)
959 {
960 	struct jheader *hp;
961 	struct jrequest *rp;
962 	char *cp;
963 
964 	hp = &reqmsg.jheader;
965 	hp->id = putshort(id);
966 	rp = &reqmsg.jrequest;
967 	rp->trigger = putshort(interval == 0);
968 	rp->interval = putshort(interval);
969 	if ((cp = jupiter_send(instance, hp)) != NULL)
970 		jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
971 }
972 
973 /* Cancel periodic message output */
974 static struct jheader canmsg = {
975 	putshort(JUPITER_SYNC), 0, 0, 0,
976 	JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC,
977 	0
978 };
979 
980 static void
981 jupiter_canmsg(struct instance *instance, u_int id)
982 {
983 	struct jheader *hp;
984 	char *cp;
985 
986 	hp = &canmsg;
987 	hp->id = putshort(id);
988 	if ((cp = jupiter_send(instance, hp)) != NULL)
989 		jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
990 }
991 
992 /* Request a single message output */
993 static struct jheader reqonemsg = {
994 	putshort(JUPITER_SYNC), 0, 0, 0,
995 	JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY,
996 	0
997 };
998 
999 static void
1000 jupiter_reqonemsg(struct instance *instance, u_int id)
1001 {
1002 	struct jheader *hp;
1003 	char *cp;
1004 
1005 	hp = &reqonemsg;
1006 	hp->id = putshort(id);
1007 	if ((cp = jupiter_send(instance, hp)) != NULL)
1008 		jupiter_debug(instance->peer, __func__, "%u: %s", id, cp);
1009 }
1010 
1011 /* Set the platform dynamics */
1012 static struct {
1013 	struct jheader jheader;
1014 	struct jplat jplat;
1015 } platmsg = {
1016 	{ putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT),
1017 	    putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0,
1018 	    JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 },
1019 	{ 0, 0, 0 }
1020 };
1021 
1022 static void
1023 jupiter_platform(struct instance *instance, u_int platform)
1024 {
1025 	struct jheader *hp;
1026 	struct jplat *pp;
1027 	char *cp;
1028 
1029 	hp = &platmsg.jheader;
1030 	pp = &platmsg.jplat;
1031 	pp->platform = putshort(platform);
1032 	if ((cp = jupiter_send(instance, hp)) != NULL)
1033 		jupiter_debug(instance->peer, __func__, "%u: %s", platform, cp);
1034 }
1035 
1036 /* Checksum "len" shorts */
1037 static u_short
1038 jupiter_cksum(u_short *sp, u_int len)
1039 {
1040 	u_short sum, x;
1041 
1042 	sum = 0;
1043 	while (len-- > 0) {
1044 		x = *sp++;
1045 		sum += getshort(x);
1046 	}
1047 	return (~sum + 1);
1048 }
1049 
1050 /* Return the size of the next message (or zero if we don't have it all yet) */
1051 static int
1052 jupiter_recv(struct instance *instance)
1053 {
1054 	int n, len, size, cc;
1055 	struct jheader *hp;
1056 	u_char *bp;
1057 	u_short *sp;
1058 
1059 	/* Must have at least a header's worth */
1060 	cc = sizeof(*hp);
1061 	size = instance->ssize;
1062 	if (size < cc)
1063 		return (0);
1064 
1065 	/* Search for the sync short if missing */
1066 	sp = instance->sbuf;
1067 	hp = (struct jheader *)sp;
1068 	if (getshort(hp->sync) != JUPITER_SYNC) {
1069 		/* Wasn't at the front, sync up */
1070 		jupiter_debug(instance->peer, __func__, "syncing");
1071 		bp = (u_char *)sp;
1072 		n = size;
1073 		while (n >= 2) {
1074 			if (bp[0] != (JUPITER_SYNC & 0xff)) {
1075 				/*
1076 				jupiter_debug(instance->peer, __func__,
1077 				    "{0x%x}", bp[0]);
1078 				*/
1079 				++bp;
1080 				--n;
1081 				continue;
1082 			}
1083 			if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
1084 				break;
1085 			/*
1086 			jupiter_debug(instance->peer, __func__,
1087 			    "{0x%x 0x%x}", bp[0], bp[1]);
1088 			*/
1089 			bp += 2;
1090 			n -= 2;
1091 		}
1092 		/*
1093 		jupiter_debug(instance->peer, __func__, "\n");
1094 		*/
1095 		/* Shuffle data to front of input buffer */
1096 		if (n > 0)
1097 			memcpy(sp, bp, n);
1098 		size = n;
1099 		instance->ssize = size;
1100 		if (size < cc || hp->sync != JUPITER_SYNC)
1101 			return (0);
1102 	}
1103 
1104 	if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
1105 	    getshort(hp->hsum)) {
1106 	    jupiter_debug(instance->peer, __func__, "bad header checksum!");
1107 		/* This is drastic but checksum errors should be rare */
1108 		instance->ssize = 0;
1109 		return (0);
1110 	}
1111 
1112 	/* Check for a payload */
1113 	len = getshort(hp->len);
1114 	if (len > 0) {
1115 		n = (len + 1) * sizeof(u_short);
1116 		/* Not enough data yet */
1117 		if (size < cc + n)
1118 			return (0);
1119 
1120 		/* Check payload checksum */
1121 		sp = (u_short *)(hp + 1);
1122 		if (jupiter_cksum(sp, len) != getshort(sp[len])) {
1123 			jupiter_debug(instance->peer,
1124 			    __func__, "bad payload checksum!");
1125 			/* This is drastic but checksum errors should be rare */
1126 			instance->ssize = 0;
1127 			return (0);
1128 		}
1129 		cc += n;
1130 	}
1131 	return (cc);
1132 }
1133 
1134 static u_int
1135 get_base_week(void)
1136 {
1137 	static int 	init_done /* = 0 */;
1138 	static u_int	base_week;
1139 
1140 	/* Get the build date, convert to days since GPS epoch and
1141 	 * finally weeks since GPS epoch.  Note that the build stamp is
1142 	 * trusted once it is fetched -- only dates before the GPS epoch
1143 	 * are not permitted. This will permit proper synchronisation
1144 	 * for a time range of 1024 weeks starting with 00:00:00 of the
1145 	 * last Sunday on or before the build time.
1146 	 *
1147 	 * If the impossible happens and fetching the build date fails,
1148 	 * a 1024-week cycle starting with 2016-01-03 is assumed to
1149 	 * avoid catastropic errors. This will work until 2035-08-19.
1150 	 */
1151 	if (!init_done) {
1152 		struct calendar bd;
1153 		if (ntpcal_get_build_date(&bd)) {
1154 			int32_t days = ntpcal_date_to_rd(&bd);
1155 			if (days > RDN_GPS_EPOCH)
1156 				days -= RDN_GPS_EPOCH;
1157 			else
1158 				days = 0;
1159 			base_week = days / 7;
1160 		} else {
1161 			base_week = 1878; /* 2016-01-03, Sunday */
1162 			msyslog(LOG_ERR,
1163 				"refclock_jupiter: ntpcal_get_build_date() failed: %s",
1164 				"using 2016-01-03 as GPS base!");
1165 		}
1166 		init_done = 1;
1167 	}
1168 	return base_week;
1169 }
1170 
1171 static u_int
1172 get_full_week(
1173 	u_int base_week,
1174 	u_int gpos_week
1175 	)
1176 {
1177 	/* Periodic extension on base week. Since the period is 1024
1178 	 * weeks and we do unsigned arithmetic here, we can do wonderful
1179 	 * things with masks and the well-defined overflow behaviour.
1180 	 */
1181 	return base_week + ((gpos_week - base_week) & 1023);
1182 }
1183 
1184 #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1185 int refclock_jupiter_bs;
1186 #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1187