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