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