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