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