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