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 /* 162 * Transfer vector 163 */ 164 struct refclock refclock_jupiter = { 165 jupiter_start, /* start up driver */ 166 jupiter_shutdown, /* shut down driver */ 167 jupiter_poll, /* transmit poll message */ 168 jupiter_control, /* (clock control) */ 169 noentry, /* (clock init) */ 170 noentry, /* (clock buginfo) */ 171 NOFLAGS /* not used */ 172 }; 173 174 /* 175 * jupiter_start - open the devices and initialize data for processing 176 */ 177 static int 178 jupiter_start( 179 int unit, 180 struct peer *peer 181 ) 182 { 183 struct refclockproc *pp; 184 struct instance *instance; 185 int fd; 186 char gpsdev[20]; 187 188 /* 189 * Open serial port 190 */ 191 snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 192 fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 193 if (fd <= 0) { 194 jupiter_debug(peer, "jupiter_start", "open %s: %m", 195 gpsdev); 196 return (0); 197 } 198 199 /* Allocate unit structure */ 200 instance = emalloc_zero(sizeof(*instance)); 201 instance->peer = peer; 202 pp = peer->procptr; 203 pp->io.clock_recv = jupiter_receive; 204 pp->io.srcclock = peer; 205 pp->io.datalen = 0; 206 pp->io.fd = fd; 207 if (!io_addclock(&pp->io)) { 208 close(fd); 209 pp->io.fd = -1; 210 free(instance); 211 return (0); 212 } 213 pp->unitptr = instance; 214 215 /* 216 * Initialize miscellaneous variables 217 */ 218 peer->precision = PRECISION; 219 pp->clockdesc = DESCRIPTION; 220 memcpy((char *)&pp->refid, REFID, 4); 221 222 #ifdef HAVE_PPSAPI 223 instance->assert = 1; 224 instance->hardpps = 0; 225 /* 226 * Start the PPSAPI interface if it is there. Default to use 227 * the assert edge and do not enable the kernel hardpps. 228 */ 229 if (time_pps_create(fd, &instance->pps_handle) < 0) { 230 instance->pps_handle = 0; 231 msyslog(LOG_ERR, 232 "refclock_jupiter: time_pps_create failed: %m"); 233 } 234 else if (!jupiter_ppsapi(instance)) 235 goto clean_up; 236 #endif /* HAVE_PPSAPI */ 237 238 /* Ensure the receiver is properly configured */ 239 if (!jupiter_config(instance)) 240 goto clean_up; 241 242 return (1); 243 244 clean_up: 245 jupiter_shutdown(unit, peer); 246 pp->unitptr = 0; 247 return (0); 248 } 249 250 /* 251 * jupiter_shutdown - shut down the clock 252 */ 253 static void 254 jupiter_shutdown(int unit, struct peer *peer) 255 { 256 struct instance *instance; 257 struct refclockproc *pp; 258 259 pp = peer->procptr; 260 instance = pp->unitptr; 261 if (!instance) 262 return; 263 264 #ifdef HAVE_PPSAPI 265 if (instance->pps_handle) { 266 time_pps_destroy(instance->pps_handle); 267 instance->pps_handle = 0; 268 } 269 #endif /* HAVE_PPSAPI */ 270 271 if (pp->io.fd != -1) 272 io_closeclock(&pp->io); 273 free(instance); 274 } 275 276 /* 277 * jupiter_config - Configure the receiver 278 */ 279 static int 280 jupiter_config(struct instance *instance) 281 { 282 jupiter_debug(instance->peer, __func__, "init receiver"); 283 284 /* 285 * Initialize the unit variables 286 */ 287 instance->sloppyclockflag = instance->peer->procptr->sloppyclockflag; 288 instance->moving = !!(instance->sloppyclockflag & CLK_FLAG2); 289 if (instance->moving) 290 jupiter_debug(instance->peer, __func__, "mobile platform"); 291 292 instance->pollcnt = 2; 293 instance->polled = 0; 294 instance->gpos_gweek = 0; 295 instance->gpos_sweek = 0; 296 instance->gweek = 0; 297 instance->lastsweek = 2 * WEEKSECS; 298 instance->timecode = 0; 299 instance->stime = 0; 300 instance->ssize = 0; 301 302 /* Stop outputting all messages */ 303 jupiter_canmsg(instance, JUPITER_ALL); 304 305 /* Request the receiver id so we can syslog the firmware version */ 306 jupiter_reqonemsg(instance, JUPITER_O_ID); 307 308 /* Flag that this the id was requested (so we don't get called again) */ 309 instance->wantid = 1; 310 311 /* Request perodic time mark pulse messages */ 312 jupiter_reqmsg(instance, JUPITER_O_PULSE, 1); 313 314 /* Request perodic geodetic position status */ 315 jupiter_reqmsg(instance, JUPITER_O_GPOS, 1); 316 317 /* Set application platform type */ 318 if (instance->moving) 319 jupiter_platform(instance, JUPITER_I_PLAT_MED); 320 else 321 jupiter_platform(instance, JUPITER_I_PLAT_LOW); 322 323 return (1); 324 } 325 326 #ifdef HAVE_PPSAPI 327 /* 328 * Initialize PPSAPI 329 */ 330 int 331 jupiter_ppsapi( 332 struct instance *instance /* unit structure pointer */ 333 ) 334 { 335 int capability; 336 337 if (time_pps_getcap(instance->pps_handle, &capability) < 0) { 338 msyslog(LOG_ERR, 339 "refclock_jupiter: time_pps_getcap failed: %m"); 340 return (0); 341 } 342 memset(&instance->pps_params, 0, sizeof(pps_params_t)); 343 if (!instance->assert) 344 instance->pps_params.mode = capability & PPS_CAPTURECLEAR; 345 else 346 instance->pps_params.mode = capability & PPS_CAPTUREASSERT; 347 if (!(instance->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 348 msyslog(LOG_ERR, 349 "refclock_jupiter: invalid capture edge %d", 350 instance->assert); 351 return (0); 352 } 353 instance->pps_params.mode |= PPS_TSFMT_TSPEC; 354 if (time_pps_setparams(instance->pps_handle, &instance->pps_params) < 0) { 355 msyslog(LOG_ERR, 356 "refclock_jupiter: time_pps_setparams failed: %m"); 357 return (0); 358 } 359 if (instance->hardpps) { 360 if (time_pps_kcbind(instance->pps_handle, PPS_KC_HARDPPS, 361 instance->pps_params.mode & ~PPS_TSFMT_TSPEC, 362 PPS_TSFMT_TSPEC) < 0) { 363 msyslog(LOG_ERR, 364 "refclock_jupiter: time_pps_kcbind failed: %m"); 365 return (0); 366 } 367 hardpps_enable = 1; 368 } 369 /* instance->peer->precision = PPS_PRECISION; */ 370 371 #if DEBUG 372 if (debug) { 373 time_pps_getparams(instance->pps_handle, &instance->pps_params); 374 jupiter_debug(instance->peer, __func__, 375 "pps capability 0x%x version %d mode 0x%x kern %d", 376 capability, instance->pps_params.api_version, 377 instance->pps_params.mode, instance->hardpps); 378 } 379 #endif 380 381 return (1); 382 } 383 384 /* 385 * Get PPSAPI timestamps. 386 * 387 * Return 0 on failure and 1 on success. 388 */ 389 static int 390 jupiter_pps(struct instance *instance) 391 { 392 pps_info_t pps_info; 393 struct timespec timeout, ts; 394 double dtemp; 395 l_fp tstmp; 396 397 /* 398 * Convert the timespec nanoseconds field to ntp l_fp units. 399 */ 400 if (instance->pps_handle == 0) 401 return 1; 402 timeout.tv_sec = 0; 403 timeout.tv_nsec = 0; 404 memcpy(&pps_info, &instance->pps_info, sizeof(pps_info_t)); 405 if (time_pps_fetch(instance->pps_handle, PPS_TSFMT_TSPEC, &instance->pps_info, 406 &timeout) < 0) 407 return 1; 408 if (instance->pps_params.mode & PPS_CAPTUREASSERT) { 409 if (pps_info.assert_sequence == 410 instance->pps_info.assert_sequence) 411 return 1; 412 ts = instance->pps_info.assert_timestamp; 413 } else if (instance->pps_params.mode & PPS_CAPTURECLEAR) { 414 if (pps_info.clear_sequence == 415 instance->pps_info.clear_sequence) 416 return 1; 417 ts = instance->pps_info.clear_timestamp; 418 } else { 419 return 1; 420 } 421 if ((instance->ts.tv_sec == ts.tv_sec) && (instance->ts.tv_nsec == ts.tv_nsec)) 422 return 1; 423 instance->ts = ts; 424 425 tstmp.l_ui = (u_int32)ts.tv_sec + JAN_1970; 426 dtemp = ts.tv_nsec * FRAC / 1e9; 427 tstmp.l_uf = (u_int32)dtemp; 428 instance->peer->procptr->lastrec = tstmp; 429 return 0; 430 } 431 #endif /* HAVE_PPSAPI */ 432 433 /* 434 * jupiter_poll - jupiter watchdog routine 435 */ 436 static void 437 jupiter_poll(int unit, struct peer *peer) 438 { 439 struct instance *instance; 440 struct refclockproc *pp; 441 442 pp = peer->procptr; 443 instance = pp->unitptr; 444 445 /* 446 * You don't need to poll this clock. It puts out timecodes 447 * once per second. If asked for a timestamp, take note. 448 * The next time a timecode comes in, it will be fed back. 449 */ 450 451 /* 452 * If we haven't had a response in a while, reset the receiver. 453 */ 454 if (instance->pollcnt > 0) { 455 instance->pollcnt--; 456 } else { 457 refclock_report(peer, CEVNT_TIMEOUT); 458 459 /* Request the receiver id to trigger a reconfig */ 460 jupiter_reqonemsg(instance, JUPITER_O_ID); 461 instance->wantid = 0; 462 } 463 464 /* 465 * polled every 64 seconds. Ask jupiter_receive to hand in 466 * a timestamp. 467 */ 468 instance->polled = 1; 469 pp->polls++; 470 } 471 472 /* 473 * jupiter_control - fudge control 474 */ 475 static void 476 jupiter_control( 477 int unit, /* unit (not used) */ 478 const struct refclockstat *in, /* input parameters (not used) */ 479 struct refclockstat *out, /* output parameters (not used) */ 480 struct peer *peer /* peer structure pointer */ 481 ) 482 { 483 struct refclockproc *pp; 484 struct instance *instance; 485 u_char sloppyclockflag; 486 487 pp = peer->procptr; 488 instance = pp->unitptr; 489 490 DTOLFP(pp->fudgetime2, &instance->limit); 491 /* Force positive value. */ 492 if (L_ISNEG(&instance->limit)) 493 L_NEG(&instance->limit); 494 495 #ifdef HAVE_PPSAPI 496 instance->assert = !(pp->sloppyclockflag & CLK_FLAG3); 497 jupiter_ppsapi(instance); 498 #endif /* HAVE_PPSAPI */ 499 500 sloppyclockflag = instance->sloppyclockflag; 501 instance->sloppyclockflag = pp->sloppyclockflag; 502 if ((instance->sloppyclockflag & CLK_FLAG2) != 503 (sloppyclockflag & CLK_FLAG2)) { 504 jupiter_debug(peer, __func__, 505 "mode switch: reset receiver"); 506 jupiter_config(instance); 507 return; 508 } 509 } 510 511 /* 512 * jupiter_receive - receive gps data 513 * Gag me! 514 */ 515 static void 516 jupiter_receive(struct recvbuf *rbufp) 517 { 518 size_t bpcnt; 519 int cc, size, ppsret; 520 time_t last_timecode; 521 u_int32 laststime; 522 const char *cp; 523 u_char *bp; 524 u_short *sp; 525 struct jid *ip; 526 struct jheader *hp; 527 struct peer *peer; 528 struct refclockproc *pp; 529 struct instance *instance; 530 l_fp tstamp; 531 532 /* Initialize pointers and read the timecode and timestamp */ 533 peer = rbufp->recv_peer; 534 pp = peer->procptr; 535 instance = pp->unitptr; 536 537 bp = (u_char *)rbufp->recv_buffer; 538 bpcnt = rbufp->recv_length; 539 540 /* This shouldn't happen */ 541 if (bpcnt > sizeof(instance->sbuf) - instance->ssize) 542 bpcnt = sizeof(instance->sbuf) - instance->ssize; 543 544 /* Append to input buffer */ 545 memcpy((u_char *)instance->sbuf + instance->ssize, bp, bpcnt); 546 instance->ssize += bpcnt; 547 548 /* While there's at least a header and we parse an intact message */ 549 while (instance->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(instance)) > 0) { 550 instance->pollcnt = 2; 551 552 tstamp = rbufp->recv_time; 553 hp = (struct jheader *)instance->sbuf; 554 sp = (u_short *)(hp + 1); 555 size = cc - sizeof(*hp); 556 switch (getshort(hp->id)) { 557 558 case JUPITER_O_PULSE: 559 if (size != sizeof(struct jpulse)) { 560 jupiter_debug(peer, __func__, 561 "pulse: len %d != %u", 562 size, (int)sizeof(struct jpulse)); 563 refclock_report(peer, CEVNT_BADREPLY); 564 break; 565 } 566 567 /* 568 * There appears to be a firmware bug related 569 * to the pulse message; in addition to the one 570 * per second messages, we get an extra pulse 571 * message once an hour (on the anniversary of 572 * the cold start). It seems to come 200 ms 573 * after the one requested. So if we've seen a 574 * pulse message in the last 210 ms, we skip 575 * this one. 576 */ 577 laststime = instance->stime; 578 instance->stime = DS2UI(((struct jpulse *)sp)->stime); 579 if (laststime != 0 && instance->stime - laststime <= 21) { 580 jupiter_debug(peer, __func__, 581 "avoided firmware bug (stime %.2f, laststime %.2f)", 582 (double)instance->stime * 0.01, (double)laststime * 0.01); 583 break; 584 } 585 586 /* Retrieve pps timestamp */ 587 ppsret = jupiter_pps(instance); 588 589 /* 590 * Add one second if msg received early 591 * (i.e. before limit, a.k.a. fudgetime2) in 592 * the second. 593 */ 594 L_SUB(&tstamp, &pp->lastrec); 595 if (!L_ISGEQ(&tstamp, &instance->limit)) 596 ++pp->lastrec.l_ui; 597 598 /* Parse timecode (even when there's no pps) */ 599 last_timecode = instance->timecode; 600 if ((cp = jupiter_parse_t(instance, sp)) != NULL) { 601 jupiter_debug(peer, __func__, 602 "pulse: %s", cp); 603 break; 604 } 605 606 /* Bail if we didn't get a pps timestamp */ 607 if (ppsret) 608 break; 609 610 /* Bail if we don't have the last timecode yet */ 611 if (last_timecode == 0) 612 break; 613 614 /* Add the new sample to a median filter */ 615 tstamp.l_ui = JAN_1970 + (u_int32)last_timecode; 616 tstamp.l_uf = 0; 617 618 refclock_process_offset(pp, tstamp, pp->lastrec, pp->fudgetime1); 619 620 /* 621 * The clock will blurt a timecode every second 622 * but we only want one when polled. If we 623 * havn't been polled, bail out. 624 */ 625 if (!instance->polled) 626 break; 627 instance->polled = 0; 628 629 /* 630 * It's a live one! Remember this time. 631 */ 632 633 pp->lastref = pp->lastrec; 634 refclock_receive(peer); 635 636 /* 637 * If we get here - what we got from the clock is 638 * OK, so say so 639 */ 640 refclock_report(peer, CEVNT_NOMINAL); 641 642 /* 643 * We have succeeded in answering the poll. 644 * Turn off the flag and return 645 */ 646 instance->polled = 0; 647 break; 648 649 case JUPITER_O_GPOS: 650 if (size != sizeof(struct jgpos)) { 651 jupiter_debug(peer, __func__, 652 "gpos: len %d != %u", 653 size, (int)sizeof(struct jgpos)); 654 refclock_report(peer, CEVNT_BADREPLY); 655 break; 656 } 657 658 if ((cp = jupiter_parse_gpos(instance, sp)) != NULL) { 659 jupiter_debug(peer, __func__, 660 "gpos: %s", cp); 661 break; 662 } 663 break; 664 665 case JUPITER_O_ID: 666 if (size != sizeof(struct jid)) { 667 jupiter_debug(peer, __func__, 668 "id: len %d != %u", 669 size, (int)sizeof(struct jid)); 670 refclock_report(peer, CEVNT_BADREPLY); 671 break; 672 } 673 /* 674 * If we got this message because the Jupiter 675 * just powered instance, it needs to be reconfigured. 676 */ 677 ip = (struct jid *)sp; 678 jupiter_debug(peer, __func__, 679 "%s chan ver %s, %s (%s)", 680 ip->chans, ip->vers, ip->date, ip->opts); 681 msyslog(LOG_DEBUG, 682 "jupiter_receive: %s chan ver %s, %s (%s)", 683 ip->chans, ip->vers, ip->date, ip->opts); 684 if (instance->wantid) 685 instance->wantid = 0; 686 else { 687 jupiter_debug(peer, __func__, "reset receiver"); 688 jupiter_config(instance); 689 /* 690 * Restore since jupiter_config() just 691 * zeroed it 692 */ 693 instance->ssize = cc; 694 } 695 break; 696 697 default: 698 jupiter_debug(peer, __func__, "unknown message id %d", 699 getshort(hp->id)); 700 break; 701 } 702 instance->ssize -= cc; 703 if (instance->ssize < 0) { 704 fprintf(stderr, "jupiter_recv: negative ssize!\n"); 705 abort(); 706 } else if (instance->ssize > 0) 707 memcpy(instance->sbuf, (u_char *)instance->sbuf + cc, instance->ssize); 708 } 709 } 710 711 static const char * 712 jupiter_parse_t(struct instance *instance, u_short *sp) 713 { 714 struct tm *tm; 715 char *cp; 716 struct jpulse *jp; 717 u_int32 sweek; 718 time_t last_timecode; 719 u_short flags; 720 721 jp = (struct jpulse *)sp; 722 723 /* The timecode is presented as seconds into the current GPS week */ 724 sweek = DS2UI(jp->sweek) % WEEKSECS; 725 726 /* 727 * If we don't know the current GPS week, calculate it from the 728 * current time. (It's too bad they didn't include this 729 * important value in the pulse message). We'd like to pick it 730 * up from one of the other messages like gpos or chan but they 731 * don't appear to be synchronous with time keeping and changes 732 * too soon (something like 10 seconds before the new GPS 733 * week). 734 * 735 * If we already know the current GPS week, increment it when 736 * we wrap into a new week. 737 */ 738 if (instance->gweek == 0) { 739 if (!instance->gpos_gweek) { 740 return ("jupiter_parse_t: Unknown gweek"); 741 } 742 743 instance->gweek = instance->gpos_gweek; 744 745 /* 746 * Fix warps. GPOS has GPS time and PULSE has UTC. 747 * Plus, GPOS need not be completely in synch with 748 * the PPS signal. 749 */ 750 if (instance->gpos_sweek >= sweek) { 751 if ((instance->gpos_sweek - sweek) > WEEKSECS / 2) 752 ++instance->gweek; 753 } 754 else { 755 if ((sweek - instance->gpos_sweek) > WEEKSECS / 2) 756 --instance->gweek; 757 } 758 } 759 else if (sweek == 0 && instance->lastsweek == WEEKSECS - 1) { 760 ++instance->gweek; 761 jupiter_debug(instance->peer, __func__, 762 "NEW gps week %u", instance->gweek); 763 } 764 765 /* 766 * See if the sweek stayed the same (this happens when there is 767 * no pps pulse). 768 * 769 * Otherwise, look for time warps: 770 * 771 * - we have stored at least one lastsweek and 772 * - the sweek didn't increase by one and 773 * - we didn't wrap to a new GPS week 774 * 775 * Then we warped. 776 */ 777 if (instance->lastsweek == sweek) 778 jupiter_debug(instance->peer, __func__, 779 "gps sweek not incrementing (%d)", 780 sweek); 781 else if (instance->lastsweek != 2 * WEEKSECS && 782 instance->lastsweek + 1 != sweek && 783 !(sweek == 0 && instance->lastsweek == WEEKSECS - 1)) 784 jupiter_debug(instance->peer, __func__, 785 "gps sweek jumped (was %d, now %d)", 786 instance->lastsweek, sweek); 787 instance->lastsweek = sweek; 788 789 /* This timecode describes next pulse */ 790 last_timecode = instance->timecode; 791 instance->timecode = 792 GPS_EPOCH + (instance->gweek * WEEKSECS) + sweek; 793 794 if (last_timecode == 0) 795 /* XXX debugging */ 796 jupiter_debug(instance->peer, __func__, 797 "UTC <none> (gweek/sweek %u/%u)", 798 instance->gweek, sweek); 799 else { 800 /* XXX debugging */ 801 tm = gmtime(&last_timecode); 802 cp = asctime(tm); 803 804 jupiter_debug(instance->peer, __func__, 805 "UTC %.24s (gweek/sweek %u/%u)", 806 cp, instance->gweek, sweek); 807 808 /* Billboard last_timecode (which is now the current time) */ 809 instance->peer->procptr->year = tm->tm_year + 1900; 810 instance->peer->procptr->day = tm->tm_yday + 1; 811 instance->peer->procptr->hour = tm->tm_hour; 812 instance->peer->procptr->minute = tm->tm_min; 813 instance->peer->procptr->second = tm->tm_sec; 814 } 815 816 flags = getshort(jp->flags); 817 818 /* Toss if not designated "valid" by the gps */ 819 if ((flags & JUPITER_O_PULSE_VALID) == 0) { 820 refclock_report(instance->peer, CEVNT_BADTIME); 821 return ("time mark not valid"); 822 } 823 824 /* We better be sync'ed to UTC... */ 825 if ((flags & JUPITER_O_PULSE_UTC) == 0) { 826 refclock_report(instance->peer, CEVNT_BADTIME); 827 return ("time mark not sync'ed to UTC"); 828 } 829 830 return (NULL); 831 } 832 833 static const char * 834 jupiter_parse_gpos(struct instance *instance, u_short *sp) 835 { 836 struct jgpos *jg; 837 time_t t; 838 struct tm *tm; 839 char *cp; 840 841 jg = (struct jgpos *)sp; 842 843 if (jg->navval != 0) { 844 /* 845 * Solution not valid. Use caution and refuse 846 * to determine GPS week from this message. 847 */ 848 instance->gpos_gweek = 0; 849 instance->gpos_sweek = 0; 850 return ("Navigation solution not valid"); 851 } 852 853 instance->gpos_sweek = DS2UI(jg->sweek); 854 instance->gpos_gweek = basedate_expand_gpsweek(getshort(jg->gweek)); 855 856 /* according to the protocol spec, the seconds-in-week cannot 857 * exceed the nominal value: Is it really necessary to normalise 858 * the seconds??? 859 */ 860 while(instance->gpos_sweek >= WEEKSECS) { 861 instance->gpos_sweek -= WEEKSECS; 862 ++instance->gpos_gweek; 863 } 864 instance->gweek = 0; 865 866 t = GPS_EPOCH + (instance->gpos_gweek * WEEKSECS) + instance->gpos_sweek; 867 tm = gmtime(&t); 868 cp = asctime(tm); 869 870 jupiter_debug(instance->peer, __func__, 871 "GPS %.24s (gweek/sweek %u/%u)", 872 cp, instance->gpos_gweek, instance->gpos_sweek); 873 return (NULL); 874 } 875 876 /* 877 * jupiter_debug - print debug messages 878 */ 879 static void 880 jupiter_debug( 881 struct peer * peer, 882 const char * function, 883 const char * fmt, 884 ... 885 ) 886 { 887 char buffer[200]; 888 va_list ap; 889 890 va_start(ap, fmt); 891 /* 892 * Print debug message to stdout 893 * In the future, we may want to get get more creative... 894 */ 895 mvsnprintf(buffer, sizeof(buffer), fmt, ap); 896 record_clock_stats(&peer->srcadr, buffer); 897 #ifdef DEBUG 898 if (debug) { 899 printf("%s: %s\n", function, buffer); 900 fflush(stdout); 901 } 902 #endif 903 904 va_end(ap); 905 } 906 907 /* Checksum and transmit a message to the Jupiter */ 908 static char * 909 jupiter_send(struct instance *instance, struct jheader *hp) 910 { 911 u_int len, size; 912 ssize_t cc; 913 u_short *sp; 914 static char errstr[132]; 915 916 size = sizeof(*hp); 917 hp->hsum = putshort(jupiter_cksum((u_short *)hp, 918 (size / sizeof(u_short)) - 1)); 919 len = getshort(hp->len); 920 if (len > 0) { 921 sp = (u_short *)(hp + 1); 922 sp[len] = putshort(jupiter_cksum(sp, len)); 923 size += (len + 1) * sizeof(u_short); 924 } 925 926 if ((cc = write(instance->peer->procptr->io.fd, (char *)hp, size)) < 0) { 927 msnprintf(errstr, sizeof(errstr), "write: %m"); 928 return (errstr); 929 } else if (cc != (int)size) { 930 snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size); 931 return (errstr); 932 } 933 return (NULL); 934 } 935 936 /* Request periodic message output */ 937 static struct { 938 struct jheader jheader; 939 struct jrequest jrequest; 940 } reqmsg = { 941 { putshort(JUPITER_SYNC), 0, 942 putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 943 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 944 JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 }, 945 { 0, 0, 0, 0 } 946 }; 947 948 /* An interval of zero means to output on trigger */ 949 static void 950 jupiter_reqmsg(struct instance *instance, u_int id, 951 u_int interval) 952 { 953 struct jheader *hp; 954 struct jrequest *rp; 955 char *cp; 956 957 hp = &reqmsg.jheader; 958 hp->id = putshort(id); 959 rp = &reqmsg.jrequest; 960 rp->trigger = putshort(interval == 0); 961 rp->interval = putshort(interval); 962 if ((cp = jupiter_send(instance, hp)) != NULL) 963 jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 964 } 965 966 /* Cancel periodic message output */ 967 static struct jheader canmsg = { 968 putshort(JUPITER_SYNC), 0, 0, 0, 969 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC, 970 0 971 }; 972 973 static void 974 jupiter_canmsg(struct instance *instance, u_int id) 975 { 976 struct jheader *hp; 977 char *cp; 978 979 hp = &canmsg; 980 hp->id = putshort(id); 981 if ((cp = jupiter_send(instance, hp)) != NULL) 982 jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 983 } 984 985 /* Request a single message output */ 986 static struct jheader reqonemsg = { 987 putshort(JUPITER_SYNC), 0, 0, 0, 988 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY, 989 0 990 }; 991 992 static void 993 jupiter_reqonemsg(struct instance *instance, u_int id) 994 { 995 struct jheader *hp; 996 char *cp; 997 998 hp = &reqonemsg; 999 hp->id = putshort(id); 1000 if ((cp = jupiter_send(instance, hp)) != NULL) 1001 jupiter_debug(instance->peer, __func__, "%u: %s", id, cp); 1002 } 1003 1004 /* Set the platform dynamics */ 1005 static struct { 1006 struct jheader jheader; 1007 struct jplat jplat; 1008 } platmsg = { 1009 { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 1010 putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 1011 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 }, 1012 { 0, 0, 0 } 1013 }; 1014 1015 static void 1016 jupiter_platform(struct instance *instance, u_int platform) 1017 { 1018 struct jheader *hp; 1019 struct jplat *pp; 1020 char *cp; 1021 1022 hp = &platmsg.jheader; 1023 pp = &platmsg.jplat; 1024 pp->platform = putshort(platform); 1025 if ((cp = jupiter_send(instance, hp)) != NULL) 1026 jupiter_debug(instance->peer, __func__, "%u: %s", platform, cp); 1027 } 1028 1029 /* Checksum "len" shorts */ 1030 static u_short 1031 jupiter_cksum(u_short *sp, u_int len) 1032 { 1033 u_short sum, x; 1034 1035 sum = 0; 1036 while (len-- > 0) { 1037 x = *sp++; 1038 sum += getshort(x); 1039 } 1040 return (~sum + 1); 1041 } 1042 1043 /* Return the size of the next message (or zero if we don't have it all yet) */ 1044 static int 1045 jupiter_recv(struct instance *instance) 1046 { 1047 int n, len, size, cc; 1048 struct jheader *hp; 1049 u_char *bp; 1050 u_short *sp; 1051 1052 /* Must have at least a header's worth */ 1053 cc = sizeof(*hp); 1054 size = instance->ssize; 1055 if (size < cc) 1056 return (0); 1057 1058 /* Search for the sync short if missing */ 1059 sp = instance->sbuf; 1060 hp = (struct jheader *)sp; 1061 if (getshort(hp->sync) != JUPITER_SYNC) { 1062 /* Wasn't at the front, sync up */ 1063 jupiter_debug(instance->peer, __func__, "syncing"); 1064 bp = (u_char *)sp; 1065 n = size; 1066 while (n >= 2) { 1067 if (bp[0] != (JUPITER_SYNC & 0xff)) { 1068 /* 1069 jupiter_debug(instance->peer, __func__, 1070 "{0x%x}", bp[0]); 1071 */ 1072 ++bp; 1073 --n; 1074 continue; 1075 } 1076 if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 1077 break; 1078 /* 1079 jupiter_debug(instance->peer, __func__, 1080 "{0x%x 0x%x}", bp[0], bp[1]); 1081 */ 1082 bp += 2; 1083 n -= 2; 1084 } 1085 /* 1086 jupiter_debug(instance->peer, __func__, "\n"); 1087 */ 1088 /* Shuffle data to front of input buffer */ 1089 if (n > 0) 1090 memcpy(sp, bp, n); 1091 size = n; 1092 instance->ssize = size; 1093 if (size < cc || hp->sync != JUPITER_SYNC) 1094 return (0); 1095 } 1096 1097 if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1098 getshort(hp->hsum)) { 1099 jupiter_debug(instance->peer, __func__, "bad header checksum!"); 1100 /* This is drastic but checksum errors should be rare */ 1101 instance->ssize = 0; 1102 return (0); 1103 } 1104 1105 /* Check for a payload */ 1106 len = getshort(hp->len); 1107 if (len > 0) { 1108 n = (len + 1) * sizeof(u_short); 1109 /* Not enough data yet */ 1110 if (size < cc + n) 1111 return (0); 1112 1113 /* Check payload checksum */ 1114 sp = (u_short *)(hp + 1); 1115 if (jupiter_cksum(sp, len) != getshort(sp[len])) { 1116 jupiter_debug(instance->peer, 1117 __func__, "bad payload checksum!"); 1118 /* This is drastic but checksum errors should be rare */ 1119 instance->ssize = 0; 1120 return (0); 1121 } 1122 cc += n; 1123 } 1124 return (cc); 1125 } 1126 1127 #else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1128 int refclock_jupiter_bs; 1129 #endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1130