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