1 /*        $NetBSD: refclock_jupiter.c,v 1.13 2024/08/18 20:47:18 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 /* This clock *REQUIRES* the PPS API to be available */
41 #if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI)
42 
43 #include "ntpd.h"
44 #include "ntp_io.h"
45 #include "ntp_refclock.h"
46 #include "ntp_unixtime.h"
47 #include "ntp_stdlib.h"
48 #include "ntp_calendar.h"
49 #include "ntp_calgps.h"
50 #include "timespecops.h"
51 
52 #include <stdio.h>
53 #include <ctype.h>
54 
55 #include "jupiter.h"
56 #include "ppsapi_timepps.h"
57 
58 #ifdef WORDS_BIGENDIAN
59 #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
60 #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
61 #else
62 #define getshort(s) ((u_short)(s))
63 #define putshort(s) ((u_short)(s))
64 #endif
65 
66 /*
67  * This driver supports the Rockwell Jupiter GPS Receiver board
68  * adapted to precision timing applications.  It requires the
69  * ppsclock line discipline or streams module described in the
70  * Line Disciplines and Streams Drivers page. It also requires a
71  * gadget box and 1-PPS level converter, such as described in the
72  * Pulse-per-second (PPS) Signal Interfacing page.
73  *
74  * It may work (with minor modifications) with other Rockwell GPS
75  * receivers such as the CityTracker.
76  */
77 
78 /*
79  * GPS Definitions
80  */
81 #define   DEVICE              "/dev/gps%d"        /* device name and unit */
82 #define   SPEED232  B9600               /* baud */
83 
84 /*
85  * Radio interface parameters
86  */
87 #define   PRECISION (-18)     /* precision assumed (about 4 us) */
88 #define   REFID     "GPS\0"             /* reference id */
89 #define   DESCRIPTION         "Rockwell Jupiter GPS Receiver" /* who we are */
90 #define   DEFFUDGETIME        0         /* default fudge time (ms) */
91 
92 /* Unix timestamp for the GPS epoch: January 6, 1980 */
93 #define GPS_EPOCH 315964800
94 
95 /* Rata Die Number of first day of GPS epoch. This is the number of days
96  * since 0000-12-31 to 1980-01-06 in the proleptic Gregorian Calendar.
97  */
98 #define RDN_GPS_EPOCH (4*146097 + 138431 + 1)
99 
100 /* Double short to unsigned int */
101 #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
102 
103 /* Double short to signed int */
104 #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0]))
105 
106 /* One week's worth of seconds */
107 #define WEEKSECS (7 * 24 * 60 * 60)
108 
109 /*
110  * Jupiter unit control structure.
111  */
112 struct instance {
113           struct peer *peer;            /* peer */
114 
115           pps_params_t pps_params;      /* pps parameters */
116           pps_info_t pps_info;                    /* last pps data */
117           pps_handle_t pps_handle;      /* pps handle */
118           u_int     assert;                       /* pps edge to use */
119           u_int     hardpps;            /* enable kernel mode */
120           l_fp                rcv_pps;  /* last pps timestamp */
121           l_fp              rcv_next;   /* rcv time of next reftime */
122           TGpsDatum ref_next; /* next GPS time stamp to use with PPS */
123           TGpsDatum piv_next; /* pivot for week date unfolding */
124           uint16_t  piv_hold; /* TTL for pivot value */
125           uint16_t  rcvtout;  /* receive timeout ticker */
126           int wantid;                             /* don't reconfig on channel id msg */
127           u_int  moving;                          /* mobile platform? */
128           u_char sloppyclockflag;                 /* fudge flags */
129           u_short sbuf[512];            /* local input buffer */
130           int ssize;                              /* space used in sbuf */
131 };
132 
133 /*
134  * Function prototypes
135  */
136 static    void      jupiter_canmsg      (struct instance * const, u_int);
137 static    u_short   jupiter_cksum       (u_short *, u_int);
138 static    int       jupiter_config      (struct instance * const);
139 static    void      jupiter_debug       (struct peer *, const char *,
140                                          const char *, ...) NTP_PRINTF(3, 4);
141 static    const char *        jupiter_parse_t     (struct instance * const, u_short *, l_fp);
142 static    const char *        jupiter_parse_gpos(struct instance * const, u_short *);
143 static    void      jupiter_platform(struct instance * const, u_int);
144 static    void      jupiter_poll        (int, struct peer *);
145 static    void      jupiter_control     (int, const struct refclockstat *,
146                                          struct refclockstat *, struct peer *);
147 static    int       jupiter_ppsapi      (struct instance * const);
148 static    int       jupiter_pps         (struct instance * const);
149 static    int       jupiter_recv        (struct instance * const);
150 static    void      jupiter_receive (struct recvbuf * const rbufp);
151 static    void      jupiter_reqmsg      (struct instance * const, u_int, u_int);
152 static    void      jupiter_reqonemsg(struct instance * const, u_int);
153 static    char *    jupiter_send        (struct instance * const, struct jheader *);
154 static    void      jupiter_shutdown(int, struct peer *);
155 static    int       jupiter_start       (int, struct peer *);
156 static    void      jupiter_ticker      (int, struct peer *);
157 
158 /*
159  * Transfer vector
160  */
161 struct    refclock refclock_jupiter = {
162           jupiter_start,                /* start up driver */
163           jupiter_shutdown,   /* shut down driver */
164           jupiter_poll,                 /* transmit poll message */
165           jupiter_control,    /* (clock control) */
166           noentry,            /* (clock init) */
167           noentry,            /* (clock buginfo) */
168           jupiter_ticker                /* 1HZ ticker */
169 };
170 
171 /*
172  * jupiter_start - open the devices and initialize data for processing
173  */
174 static int
jupiter_start(int unit,struct peer * peer)175 jupiter_start(
176           int unit,
177           struct peer *peer
178           )
179 {
180           struct refclockproc * const pp = peer->procptr;
181           struct instance * up;
182           int fd;
183           char gpsdev[20];
184 
185           /*
186            * Open serial port
187            */
188           snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit);
189           fd = refclock_open(&peer->srcadr, gpsdev, SPEED232, LDISC_RAW);
190           if (fd <= 0) {
191                     jupiter_debug(peer, "jupiter_start", "open %s: %s",
192                                     gpsdev, strerror(errno));
193                     return (0);
194           }
195 
196           /* Allocate unit structure */
197           up = emalloc_zero(sizeof(*up));
198           up->peer = peer;
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(up);
207                     return (0);
208           }
209           pp->unitptr = up;
210 
211           /*
212            * Initialize miscellaneous variables
213            */
214           peer->precision = PRECISION;
215           pp->clockdesc = DESCRIPTION;
216           memcpy((char *)&pp->refid, REFID, 4);
217 
218           up->assert = 1;
219           up->hardpps = 0;
220           /*
221            * Start the PPSAPI interface if it is there. Default to use
222            * the assert edge and do not enable the kernel hardpps.
223            */
224           if (time_pps_create(fd, &up->pps_handle) < 0) {
225                     up->pps_handle = 0;
226                     msyslog(LOG_ERR,
227                               "refclock_jupiter: time_pps_create failed: %m");
228           }
229           else if (!jupiter_ppsapi(up))
230                     goto clean_up;
231 
232           /* Ensure the receiver is properly configured */
233           if (!jupiter_config(up))
234                     goto clean_up;
235 
236           jupiter_pps(up);    /* get current PPS state */
237           return (1);
238 
239 clean_up:
240           jupiter_shutdown(unit, peer);
241           pp->unitptr = 0;
242           return (0);
243 }
244 
245 /*
246  * jupiter_shutdown - shut down the clock
247  */
248 static void
jupiter_shutdown(int unit,struct peer * peer)249 jupiter_shutdown(int unit, struct peer *peer)
250 {
251           struct refclockproc * const pp = peer->procptr;
252           struct instance *     const up = pp->unitptr;
253 
254           if (!up)
255                     return;
256 
257           if (up->pps_handle) {
258                     time_pps_destroy(up->pps_handle);
259                     up->pps_handle = 0;
260           }
261 
262           if (pp->io.fd != -1)
263                     io_closeclock(&pp->io);
264           free(up);
265 }
266 
267 /*
268  * jupiter_config - Configure the receiver
269  */
270 static int
jupiter_config(struct instance * const up)271 jupiter_config(struct instance * const up)
272 {
273           jupiter_debug(up->peer, __func__, "init receiver");
274 
275           /*
276            * Initialize the unit variables
277            */
278           up->sloppyclockflag = up->peer->procptr->sloppyclockflag;
279           up->moving = !!(up->sloppyclockflag & CLK_FLAG2);
280           if (up->moving)
281                     jupiter_debug(up->peer, __func__, "mobile platform");
282 
283           ZERO(up->rcv_next);
284           ZERO(up->ref_next);
285           ZERO(up->piv_next);
286           up->ssize = 0;
287 
288           /* Stop outputting all messages */
289           jupiter_canmsg(up, JUPITER_ALL);
290 
291           /* Request the receiver id so we can syslog the firmware version */
292           jupiter_reqonemsg(up, JUPITER_O_ID);
293 
294           /* Flag that this the id was requested (so we don't get called again) */
295           up->wantid = 1;
296 
297           /* Request perodic time mark pulse messages */
298           jupiter_reqmsg(up, JUPITER_O_PULSE, 1);
299 
300           /* Request perodic geodetic position status */
301           jupiter_reqmsg(up, JUPITER_O_GPOS, 1);
302 
303           /* Set application platform type */
304           if (up->moving)
305                     jupiter_platform(up, JUPITER_I_PLAT_MED);
306           else
307                     jupiter_platform(up, JUPITER_I_PLAT_LOW);
308 
309           return (1);
310 }
311 
312 static void
jupiter_checkpps(struct refclockproc * const pp,struct instance * const up)313 jupiter_checkpps(
314           struct refclockproc * const pp,
315           struct instance *     const up
316           )
317 {
318           l_fp                tstamp, delta;
319           struct calendar     cd;
320 
321           if (jupiter_pps(up) || !up->piv_next.weeks)
322                     return;
323 
324           /* check delay between pulse message and pulse. */
325           delta = up->rcv_pps;                    /* set by jupiter_pps() */
326           L_SUB(&delta, &up->rcv_next); /* recv time pulse message */
327           if (delta.l_ui != 0 || delta.l_uf >= 0xC0000000) {
328                     up->ref_next.weeks = 0;       /* consider as consumed... */
329                     return;
330           }
331 
332           pp->lastrec = up->rcv_pps;
333           tstamp = ntpfp_from_gpsdatum(&up->ref_next);
334           refclock_process_offset(pp, tstamp, up->rcv_pps, pp->fudgetime1);
335           up->rcvtout = 2;
336 
337           gpscal_to_calendar(&cd, &up->ref_next);
338           refclock_save_lcode(pp, ntpcal_iso8601std(NULL, 0, &cd),
339                                   (size_t)-1);
340           up->ref_next.weeks = 0;       /* consumed... */
341 }
342 
343 /*
344  * jupiter_ticker - process periodic checks
345  */
346 static void
jupiter_ticker(int unit,struct peer * peer)347 jupiter_ticker(int unit, struct peer *peer)
348 {
349           struct refclockproc * const pp = peer->procptr;
350           struct instance *     const up = pp->unitptr;
351 
352           if (!up)
353                     return;
354 
355           /* check if we can add another sample now */
356           jupiter_checkpps(pp, up);
357 
358           /* check the pivot update cycle */
359           if (up->piv_hold && !--up->piv_hold)
360                     ZERO(up->piv_next);
361 
362           if (up->rcvtout)
363                     --up->rcvtout;
364           else if (pp->coderecv != pp->codeproc)
365                     refclock_samples_expire(pp, 1);
366 }
367 
368 /*
369  * Initialize PPSAPI
370  */
371 int
jupiter_ppsapi(struct instance * const up)372 jupiter_ppsapi(
373           struct instance * const up    /* unit structure pointer */
374           )
375 {
376           int capability;
377 
378           if (time_pps_getcap(up->pps_handle, &capability) < 0) {
379                     msyslog(LOG_ERR,
380                         "refclock_jupiter: time_pps_getcap failed: %m");
381                     return (0);
382           }
383           memset(&up->pps_params, 0, sizeof(pps_params_t));
384           if (!up->assert)
385                     up->pps_params.mode = capability & PPS_CAPTURECLEAR;
386           else
387                     up->pps_params.mode = capability & PPS_CAPTUREASSERT;
388           if (!(up->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
389                     msyslog(LOG_ERR,
390                         "refclock_jupiter: invalid capture edge %d",
391                         up->assert);
392                     return (0);
393           }
394           up->pps_params.mode |= PPS_TSFMT_TSPEC;
395           if (time_pps_setparams(up->pps_handle, &up->pps_params) < 0) {
396                     msyslog(LOG_ERR,
397                         "refclock_jupiter: time_pps_setparams failed: %m");
398                     return (0);
399           }
400           if (up->hardpps) {
401                     if (time_pps_kcbind(up->pps_handle, PPS_KC_HARDPPS,
402                                             up->pps_params.mode & ~PPS_TSFMT_TSPEC,
403                                             PPS_TSFMT_TSPEC) < 0) {
404                               msyslog(LOG_ERR,
405                                   "refclock_jupiter: time_pps_kcbind failed: %m");
406                               return (0);
407                     }
408                     hardpps_enable = 1;
409           }
410 /*        up->peer->precision = PPS_PRECISION; */
411 
412 #if DEBUG
413           if (debug) {
414                     time_pps_getparams(up->pps_handle, &up->pps_params);
415                     jupiter_debug(up->peer, __func__,
416                               "pps capability 0x%x version %d mode 0x%x kern %d",
417                               capability, up->pps_params.api_version,
418                               up->pps_params.mode, up->hardpps);
419           }
420 #endif
421 
422           return (1);
423 }
424 
425 /*
426  * Get PPSAPI timestamps.
427  *
428  * Return 0 on failure and 1 on success.
429  */
430 static int
jupiter_pps(struct instance * const up)431 jupiter_pps(struct instance * const up)
432 {
433           pps_info_t pps_info;
434           struct timespec timeout, ts;
435           l_fp tstmp;
436 
437           /*
438            * Convert the timespec nanoseconds field to ntp l_fp units.
439            */
440           if (up->pps_handle == 0)
441                     return 1;
442           timeout.tv_sec = 0;
443           timeout.tv_nsec = 0;
444           memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t));
445           if (time_pps_fetch(up->pps_handle, PPS_TSFMT_TSPEC, &up->pps_info,
446               &timeout) < 0)
447                     return 1;
448           if (up->pps_params.mode & PPS_CAPTUREASSERT) {
449                     if (pps_info.assert_sequence ==
450                         up->pps_info.assert_sequence)
451                               return 1;
452                     ts = up->pps_info.assert_timestamp;
453           } else if (up->pps_params.mode & PPS_CAPTURECLEAR) {
454                     if (pps_info.clear_sequence ==
455                         up->pps_info.clear_sequence)
456                               return 1;
457                     ts = up->pps_info.clear_timestamp;
458           } else {
459                     return 1;
460           }
461 
462           tstmp = tspec_stamp_to_lfp(ts);
463           if (L_ISEQU(&tstmp, &up->rcv_pps))
464                     return 1;
465 
466           up->rcv_pps = tstmp;
467           return 0;
468 }
469 
470 /*
471  * jupiter_poll - jupiter watchdog routine
472  */
473 static void
jupiter_poll(int unit,struct peer * peer)474 jupiter_poll(int unit, struct peer *peer)
475 {
476           struct refclockproc * const pp = peer->procptr;
477           struct instance *     const up = pp->unitptr;
478 
479           pp->polls++;
480 
481           /*
482            * If we have new samples since last poll, everything is fine.
483            * if not, blarb loudly.
484            */
485           if (pp->coderecv != pp->codeproc) {
486                     refclock_receive(peer);
487                     refclock_report(peer, CEVNT_NOMINAL);
488           } else {
489                     refclock_report(peer, CEVNT_TIMEOUT);
490 
491                     /* Request the receiver id to trigger a reconfig */
492                     jupiter_reqonemsg(up, JUPITER_O_ID);
493                     up->wantid = 0;
494           }
495 }
496 
497 /*
498  * jupiter_control - fudge control
499  */
500 static void
jupiter_control(int unit,const struct refclockstat * in,struct refclockstat * out,struct peer * peer)501 jupiter_control(
502           int unit,           /* unit (not used) */
503           const struct refclockstat *in, /* input parameters (not used) */
504           struct refclockstat *out, /* output parameters (not used) */
505           struct peer *peer   /* peer structure pointer */
506           )
507 {
508           struct refclockproc * const pp = peer->procptr;
509           struct instance *     const up = pp->unitptr;
510 
511           u_char sloppyclockflag;
512 
513           up->assert = !(pp->sloppyclockflag & CLK_FLAG3);
514           jupiter_ppsapi(up);
515 
516           sloppyclockflag = up->sloppyclockflag;
517           up->sloppyclockflag = pp->sloppyclockflag;
518           if ((up->sloppyclockflag & CLK_FLAG2) !=
519               (sloppyclockflag & CLK_FLAG2)) {
520                     jupiter_debug(peer, __func__,
521                         "mode switch: reset receiver");
522                     jupiter_config(up);
523                     return;
524           }
525 }
526 
527 /*
528  * jupiter_receive - receive gps data
529  * Gag me!
530  */
531 static void
jupiter_receive(struct recvbuf * const rbufp)532 jupiter_receive(struct recvbuf * const rbufp)
533 {
534           struct peer *         const peer = rbufp->recv_peer;
535           struct refclockproc * const pp   = peer->procptr;
536           struct instance *     const up   = pp->unitptr;
537 
538           size_t bpcnt;
539           int cc, size;
540           const char *cp;
541           u_char *bp;
542           u_short *sp;
543           struct jid *ip;
544           struct jheader *hp;
545 
546           /* Initialize pointers and read the timecode and timestamp */
547           bp = (u_char *)rbufp->recv_buffer;
548           bpcnt = rbufp->recv_length;
549 
550           /* This shouldn't happen */
551           if (bpcnt > sizeof(up->sbuf) - up->ssize)
552                     bpcnt = sizeof(up->sbuf) - up->ssize;
553 
554           /* Append to input buffer */
555           memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt);
556           up->ssize += bpcnt;
557 
558           /* While there's at least a header and we parse an intact message */
559           while (up->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(up)) > 0) {
560                     hp = (struct jheader *)up->sbuf;
561                     sp = (u_short *)(hp + 1);
562                     size = cc - sizeof(*hp);
563                     switch (getshort(hp->id)) {
564 
565                     case JUPITER_O_PULSE:
566                               /* first see if we can push another sample: */
567                               jupiter_checkpps(pp, up);
568 
569                               if (size != sizeof(struct jpulse)) {
570                                         jupiter_debug(peer, __func__,
571                                             "pulse: len %d != %u",
572                                             size, (int)sizeof(struct jpulse));
573                                         refclock_report(peer, CEVNT_BADREPLY);
574                                         break;
575                               }
576 
577                               /* Parse timecode (even when there's no pps)
578                                *
579                                * There appears to be a firmware bug related to
580                                * the pulse message; in addition to the one per
581                                * second messages, we get an extra pulse
582                                * message once an hour (on the anniversary of
583                                * the cold start). It seems to come 200 ms
584                                * after the one requested.
585                                *
586                                * But since we feed samples only when a new PPS
587                                * pulse is found we can simply ignore that and
588                                * aggregate/update any existing timing message.
589                                */
590                               if ((cp = jupiter_parse_t(up, sp, rbufp->recv_time)) != NULL) {
591                                         jupiter_debug(peer, __func__,
592                                             "pulse: %s", cp);
593                               }
594                               break;
595 
596                     case JUPITER_O_GPOS:
597                               if (size != sizeof(struct jgpos)) {
598                                         jupiter_debug(peer, __func__,
599                                             "gpos: len %d != %u",
600                                             size, (int)sizeof(struct jgpos));
601                                         refclock_report(peer, CEVNT_BADREPLY);
602                                         break;
603                               }
604 
605                               if ((cp = jupiter_parse_gpos(up, sp)) != NULL) {
606                                         jupiter_debug(peer, __func__,
607                                             "gpos: %s", cp);
608                                         break;
609                               }
610                               break;
611 
612                     case JUPITER_O_ID:
613                               if (size != sizeof(struct jid)) {
614                                         jupiter_debug(peer, __func__,
615                                             "id: len %d != %u",
616                                             size, (int)sizeof(struct jid));
617                                         refclock_report(peer, CEVNT_BADREPLY);
618                                         break;
619                               }
620                               /*
621                                * If we got this message because the Jupiter
622                                * just powered instance, it needs to be reconfigured.
623                                */
624                               ip = (struct jid *)sp;
625                               jupiter_debug(peer, __func__,
626                                   "%s chan ver %s, %s (%s)",
627                                   ip->chans, ip->vers, ip->date, ip->opts);
628                               msyslog(LOG_DEBUG,
629                                   "jupiter_receive: %s chan ver %s, %s (%s)",
630                                   ip->chans, ip->vers, ip->date, ip->opts);
631                               if (up->wantid)
632                                         up->wantid = 0;
633                               else {
634                                         jupiter_debug(peer, __func__, "reset receiver");
635                                         jupiter_config(up);
636                                         /*
637                                          * Restore since jupiter_config() just
638                                          * zeroed it
639                                          */
640                                         up->ssize = cc;
641                               }
642                               break;
643 
644                     default:
645                               jupiter_debug(peer, __func__, "unknown message id %d",
646                                   getshort(hp->id));
647                               break;
648                     }
649                     up->ssize -= cc;
650                     if (up->ssize < 0) {
651                               fprintf(stderr, "jupiter_recv: negative ssize!\n");
652                               abort();
653                     } else if (up->ssize > 0)
654                               memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize);
655           }
656 }
657 
658 static const char *
jupiter_parse_t(struct instance * const up,u_short * sp,l_fp rcvtime)659 jupiter_parse_t(
660           struct instance * const up,
661           u_short *               sp,
662           l_fp               rcvtime
663           )
664 {
665           struct jpulse *jp;
666           u_int32 sweek;
667           u_short flags;
668           l_fp fofs;
669 
670           jp = (struct jpulse *)sp;
671           flags = getshort(jp->flags);
672 
673           /* Toss if not designated "valid" by the gps.
674            * !!NOTE!! do *not* kill data received so far!
675            */
676           if ((flags & JUPITER_O_PULSE_VALID) == 0) {
677                     refclock_report(up->peer, CEVNT_BADTIME);
678                     return ("time mark not valid");
679           }
680 
681           up->rcv_next = rcvtime; /* remember when this happened */
682 
683           /* The timecode is presented as seconds into the current GPS week */
684           sweek = DS2UI(jp->sweek) % WEEKSECS;
685           /* check if we have to apply the UTC offset ourselves */
686           if ((flags & JUPITER_O_PULSE_UTC) == 0) {
687                     struct timespec tofs;
688                     tofs.tv_sec  = getshort(jp->offs);
689                     tofs.tv_nsec = DS2I(jp->offns);
690                     fofs = tspec_intv_to_lfp(tofs);
691                     L_NEG(&fofs);
692           } else {
693                     ZERO(fofs);
694           }
695 
696           /*
697            * If we don't know the current GPS week, calculate it from the
698            * current time. (It's too bad they didn't include this
699            * important value in the pulse message).
700            *
701            * So we pick the pivot value from the other messages like gpos
702            * or chan if we can. Of course, the PULSE message can be in UTC
703            * or GPS time scale, and the other messages are simply always
704            * GPS time.
705            *
706            * But as long as the difference between the time stamps is less
707            * than a half week, the unfolding of a week time is unambigeous
708            * and well suited for the problem we have here. And we won't
709            * see *that* many leap seconds, ever.
710            */
711           if (up->piv_next.weeks) {
712                     up->ref_next = gpscal_from_weektime2(
713                               sweek, fofs, &up->piv_next);
714                     up->piv_next = up->ref_next;
715           } else {
716                     up->ref_next = gpscal_from_weektime1(
717                               sweek, fofs, rcvtime);
718           }
719 
720 
721 
722           return (NULL);
723 }
724 
725 static const char *
jupiter_parse_gpos(struct instance * const up,u_short * sp)726 jupiter_parse_gpos(
727           struct instance * const up,
728           u_short *               sp
729           )
730 {
731           struct jgpos *jg;
732           struct calendar     tref;
733           char *cp;
734           struct timespec tofs;
735           uint16_t  raw_week;
736           uint32_t  raw_secs;
737 
738           jg = (struct jgpos *)sp;
739 
740           if (jg->navval != 0) {
741                     /*
742                      * Solution not valid. Use caution and refuse
743                      * to determine GPS week from this message.
744                      */
745                     return ("Navigation solution not valid");
746           }
747 
748           raw_week = getshort(jg->gweek);
749           raw_secs = DS2UI(jg->sweek);
750           tofs.tv_sec  = 0;
751           tofs.tv_nsec = DS2UI(jg->nsweek);
752           up->piv_next = gpscal_from_gpsweek(raw_week, raw_secs,
753                                                      tspec_intv_to_lfp(tofs));
754           up->piv_hold = 60;
755 
756           gpscal_to_calendar(&tref, &up->piv_next);
757           cp = ntpcal_iso8601std(NULL, 0, &tref);
758           jupiter_debug(up->peer, __func__,
759                     "GPS %s (gweek/sweek %hu/%u)",
760                           cp, (unsigned short)raw_week, (unsigned int)raw_secs);
761           return (NULL);
762 }
763 
764 /*
765  * jupiter_debug - print debug messages
766  */
767 static void
jupiter_debug(struct peer * peer,const char * function,const char * fmt,...)768 jupiter_debug(
769           struct peer *       peer,
770           const char *        function,
771           const char *        fmt,
772           ...
773           )
774 {
775           char      buffer[200];
776           va_list   ap;
777 
778           va_start(ap, fmt);
779           /*
780            * Print debug message to stdout
781            * In the future, we may want to get get more creative...
782            */
783           mvsnprintf(buffer, sizeof(buffer), fmt, ap);
784           record_clock_stats(&peer->srcadr, buffer);
785 #ifdef DEBUG
786           if (debug) {
787                     printf("%s: %s\n", function, buffer);
788                     fflush(stdout);
789           }
790 #endif
791 
792           va_end(ap);
793 }
794 
795 /* Checksum and transmit a message to the Jupiter */
796 static char *
jupiter_send(struct instance * const up,struct jheader * hp)797 jupiter_send(
798           struct instance * const up,
799           struct jheader *        hp
800           )
801 {
802           u_int len, size;
803           ssize_t cc;
804           u_short *sp;
805           static char errstr[132];
806 
807           size = sizeof(*hp);
808           hp->hsum = putshort(jupiter_cksum((u_short *)hp,
809               (size / sizeof(u_short)) - 1));
810           len = getshort(hp->len);
811           if (len > 0) {
812                     sp = (u_short *)(hp + 1);
813                     sp[len] = putshort(jupiter_cksum(sp, len));
814                     size += (len + 1) * sizeof(u_short);
815           }
816 
817           if ((cc = write(up->peer->procptr->io.fd, (char *)hp, size)) < 0) {
818                     msnprintf(errstr, sizeof(errstr), "write: %m");
819                     return (errstr);
820           } else if (cc != (int)size) {
821                     snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size);
822                     return (errstr);
823           }
824           return (NULL);
825 }
826 
827 /* Request periodic message output */
828 static struct {
829           struct jheader jheader;
830           struct jrequest jrequest;
831 } reqmsg = {
832           { putshort(JUPITER_SYNC), 0,
833               putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1),
834               0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK |
835               JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 },
836           { 0, 0, 0, 0 }
837 };
838 
839 /* An interval of zero means to output on trigger */
840 static void
jupiter_reqmsg(struct instance * const up,u_int id,u_int interval)841 jupiter_reqmsg(
842           struct instance * const up,
843           u_int                   id,
844           u_int             interval
845           )
846 {
847           struct jheader *hp;
848           struct jrequest *rp;
849           char *cp;
850 
851           hp = &reqmsg.jheader;
852           hp->id = putshort(id);
853           rp = &reqmsg.jrequest;
854           rp->trigger = putshort(interval == 0);
855           rp->interval = putshort(interval);
856           if ((cp = jupiter_send(up, hp)) != NULL)
857                     jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
858 }
859 
860 /* Cancel periodic message output */
861 static struct jheader canmsg = {
862           putshort(JUPITER_SYNC), 0, 0, 0,
863           JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC,
864           0
865 };
866 
867 static void
jupiter_canmsg(struct instance * const up,u_int id)868 jupiter_canmsg(
869           struct instance * const up,
870           u_int                   id
871           )
872 {
873           struct jheader *hp;
874           char *cp;
875 
876           hp = &canmsg;
877           hp->id = putshort(id);
878           if ((cp = jupiter_send(up, hp)) != NULL)
879                     jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
880 }
881 
882 /* Request a single message output */
883 static struct jheader reqonemsg = {
884           putshort(JUPITER_SYNC), 0, 0, 0,
885           JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY,
886           0
887 };
888 
889 static void
jupiter_reqonemsg(struct instance * const up,u_int id)890 jupiter_reqonemsg(
891           struct instance * const up,
892           u_int                   id
893           )
894 {
895           struct jheader *hp;
896           char *cp;
897 
898           hp = &reqonemsg;
899           hp->id = putshort(id);
900           if ((cp = jupiter_send(up, hp)) != NULL)
901                     jupiter_debug(up->peer, __func__, "%u: %s", id, cp);
902 }
903 
904 /* Set the platform dynamics */
905 static struct {
906           struct jheader jheader;
907           struct jplat jplat;
908 } platmsg = {
909           { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT),
910               putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0,
911               JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 },
912           { 0, 0, 0 }
913 };
914 
915 static void
jupiter_platform(struct instance * const up,u_int platform)916 jupiter_platform(
917           struct instance * const up,
918           u_int             platform
919           )
920 {
921           struct jheader *hp;
922           struct jplat *pp;
923           char *cp;
924 
925           hp = &platmsg.jheader;
926           pp = &platmsg.jplat;
927           pp->platform = putshort(platform);
928           if ((cp = jupiter_send(up, hp)) != NULL)
929                     jupiter_debug(up->peer, __func__, "%u: %s", platform, cp);
930 }
931 
932 /* Checksum "len" shorts */
933 static u_short
jupiter_cksum(u_short * sp,u_int len)934 jupiter_cksum(u_short *sp, u_int len)
935 {
936           u_short sum, x;
937 
938           sum = 0;
939           while (len-- > 0) {
940                     x = *sp++;
941                     sum += getshort(x);
942           }
943           return (~sum + 1);
944 }
945 
946 /* Return the size of the next message (or zero if we don't have it all yet) */
947 static int
jupiter_recv(struct instance * const up)948 jupiter_recv(
949           struct instance * const up
950           )
951 {
952           int n, len, size, cc;
953           struct jheader *hp;
954           u_char *bp;
955           u_short *sp;
956 
957           /* Must have at least a header's worth */
958           cc = sizeof(*hp);
959           size = up->ssize;
960           if (size < cc)
961                     return (0);
962 
963           /* Search for the sync short if missing */
964           sp = up->sbuf;
965           hp = (struct jheader *)sp;
966           if (getshort(hp->sync) != JUPITER_SYNC) {
967                     /* Wasn't at the front, sync up */
968                     jupiter_debug(up->peer, __func__, "syncing");
969                     bp = (u_char *)sp;
970                     n = size;
971                     while (n >= 2) {
972                               if (bp[0] != (JUPITER_SYNC & 0xff)) {
973                                         /*
974                                         jupiter_debug(up->peer, __func__,
975                                             "{0x%x}", bp[0]);
976                                         */
977                                         ++bp;
978                                         --n;
979                                         continue;
980                               }
981                               if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff))
982                                         break;
983                               /*
984                               jupiter_debug(up->peer, __func__,
985                                   "{0x%x 0x%x}", bp[0], bp[1]);
986                               */
987                               bp += 2;
988                               n -= 2;
989                     }
990                     /*
991                     jupiter_debug(up->peer, __func__, "\n");
992                     */
993                     /* Shuffle data to front of input buffer */
994                     if (n > 0)
995                               memcpy(sp, bp, n);
996                     size = n;
997                     up->ssize = size;
998                     if (size < cc || hp->sync != JUPITER_SYNC)
999                               return (0);
1000           }
1001 
1002           if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) !=
1003               getshort(hp->hsum)) {
1004               jupiter_debug(up->peer, __func__, "bad header checksum!");
1005                     /* This is drastic but checksum errors should be rare */
1006                     up->ssize = 0;
1007                     return (0);
1008           }
1009 
1010           /* Check for a payload */
1011           len = getshort(hp->len);
1012           if (len > 0) {
1013                     n = (len + 1) * sizeof(u_short);
1014                     /* Not enough data yet */
1015                     if (size < cc + n)
1016                               return (0);
1017 
1018                     /* Check payload checksum */
1019                     sp = (u_short *)(hp + 1);
1020                     if (jupiter_cksum(sp, len) != getshort(sp[len])) {
1021                               jupiter_debug(up->peer,
1022                                   __func__, "bad payload checksum!");
1023                               /* This is drastic but checksum errors should be rare */
1024                               up->ssize = 0;
1025                               return (0);
1026                     }
1027                     cc += n;
1028           }
1029           return (cc);
1030 }
1031 
1032 #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1033 NONEMPTY_TRANSLATION_UNIT
1034 #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */
1035