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