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