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