1 /* $NetBSD: refclock_jupiter.c,v 1.12 2020/05/25 20:47:25 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 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(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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 * 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 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 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 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 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 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 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 int refclock_jupiter_bs; 1034 #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1035