refclock_jupiter.c revision 358659
11558Srgrimes/* 274531Sru * Copyright (c) 1997, 1998, 2003 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 5109725Sru * Redistribution and use in source and binary forms, with or without 6109597Sjmallett * modification, are permitted provided that the following conditions 774815Sru * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 9207145Sjeff * notice, this list of conditions and the following disclaimer. 10207145Sjeff * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * 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/* This clock *REQUIRES* the PPS API to be available */ 39#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(HAVE_PPSAPI) 40 41#include "ntpd.h" 42#include "ntp_io.h" 43#include "ntp_refclock.h" 44#include "ntp_unixtime.h" 45#include "ntp_stdlib.h" 46#include "ntp_calendar.h" 47#include "ntp_calgps.h" 48#include "timespecops.h" 49 50#include <stdio.h> 51#include <ctype.h> 52 53#include "jupiter.h" 54#include "ppsapi_timepps.h" 55 56#ifdef WORDS_BIGENDIAN 57#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 58#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 59#else 60#define getshort(s) ((u_short)(s)) 61#define putshort(s) ((u_short)(s)) 62#endif 63 64/* 65 * This driver supports the Rockwell Jupiter GPS Receiver board 66 * adapted to precision timing applications. It requires the 67 * ppsclock line discipline or streams module described in the 68 * Line Disciplines and Streams Drivers page. It also requires a 69 * gadget box and 1-PPS level converter, such as described in the 70 * Pulse-per-second (PPS) Signal Interfacing page. 71 * 72 * It may work (with minor modifications) with other Rockwell GPS 73 * receivers such as the CityTracker. 74 */ 75 76/* 77 * GPS Definitions 78 */ 79#define DEVICE "/dev/gps%d" /* device name and unit */ 80#define SPEED232 B9600 /* baud */ 81 82/* 83 * Radio interface parameters 84 */ 85#define PRECISION (-18) /* precision assumed (about 4 us) */ 86#define REFID "GPS\0" /* reference id */ 87#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ 88#define DEFFUDGETIME 0 /* default fudge time (ms) */ 89 90/* Unix timestamp for the GPS epoch: January 6, 1980 */ 91#define GPS_EPOCH 315964800 92 93/* Rata Die Number of first day of GPS epoch. This is the number of days 94 * since 0000-12-31 to 1980-01-06 in the proleptic Gregorian Calendar. 95 */ 96#define RDN_GPS_EPOCH (4*146097 + 138431 + 1) 97 98/* Double short to unsigned int */ 99#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 100 101/* Double short to signed int */ 102#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 103 104/* One week's worth of seconds */ 105#define WEEKSECS (7 * 24 * 60 * 60) 106 107/* 108 * Jupiter unit control structure. 109 */ 110struct instance { 111 struct peer *peer; /* peer */ 112 113 pps_params_t pps_params; /* pps parameters */ 114 pps_info_t pps_info; /* last pps data */ 115 pps_handle_t pps_handle; /* pps handle */ 116 u_int assert; /* pps edge to use */ 117 u_int hardpps; /* enable kernel mode */ 118 l_fp rcv_pps; /* last pps timestamp */ 119 l_fp rcv_next; /* rcv time of next reftime */ 120 TGpsDatum ref_next; /* next GPS time stamp to use with PPS */ 121 TGpsDatum piv_next; /* pivot for week date unfolding */ 122 uint16_t piv_hold; /* TTL for pivot value */ 123 uint16_t rcvtout; /* receive timeout ticker */ 124 int wantid; /* don't reconfig on channel id msg */ 125 u_int moving; /* mobile platform? */ 126 u_char sloppyclockflag; /* fudge flags */ 127 u_short sbuf[512]; /* local input buffer */ 128 int ssize; /* space used in sbuf */ 129}; 130 131/* 132 * Function prototypes 133 */ 134static void jupiter_canmsg (struct instance * const, u_int); 135static u_short jupiter_cksum (u_short *, u_int); 136static int jupiter_config (struct instance * const); 137static void jupiter_debug (struct peer *, const char *, 138 const char *, ...) NTP_PRINTF(3, 4); 139static const char * jupiter_parse_t (struct instance * const, u_short *, l_fp); 140static const char * jupiter_parse_gpos(struct instance * const, u_short *); 141static void jupiter_platform(struct instance * const, u_int); 142static void jupiter_poll (int, struct peer *); 143static void jupiter_control (int, const struct refclockstat *, 144 struct refclockstat *, struct peer *); 145static int jupiter_ppsapi (struct instance * const); 146static int jupiter_pps (struct instance * const); 147static int jupiter_recv (struct instance * const); 148static void jupiter_receive (struct recvbuf * const rbufp); 149static void jupiter_reqmsg (struct instance * const, u_int, u_int); 150static void jupiter_reqonemsg(struct instance * const, u_int); 151static char * jupiter_send (struct instance * const, struct jheader *); 152static void jupiter_shutdown(int, struct peer *); 153static int jupiter_start (int, struct peer *); 154static void jupiter_ticker (int, struct peer *); 155 156/* 157 * Transfer vector 158 */ 159struct refclock refclock_jupiter = { 160 jupiter_start, /* start up driver */ 161 jupiter_shutdown, /* shut down driver */ 162 jupiter_poll, /* transmit poll message */ 163 jupiter_control, /* (clock control) */ 164 noentry, /* (clock init) */ 165 noentry, /* (clock buginfo) */ 166 jupiter_ticker /* 1HZ ticker */ 167}; 168 169/* 170 * jupiter_start - open the devices and initialize data for processing 171 */ 172static int 173jupiter_start( 174 int unit, 175 struct peer *peer 176 ) 177{ 178 struct refclockproc * const pp = peer->procptr; 179 struct instance * up; 180 int fd; 181 char gpsdev[20]; 182 183 /* 184 * Open serial port 185 */ 186 snprintf(gpsdev, sizeof(gpsdev), DEVICE, unit); 187 fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); 188 if (fd <= 0) { 189 jupiter_debug(peer, "jupiter_start", "open %s: %m", 190 gpsdev); 191 return (0); 192 } 193 194 /* Allocate unit structure */ 195 up = emalloc_zero(sizeof(*up)); 196 up->peer = peer; 197 pp->io.clock_recv = jupiter_receive; 198 pp->io.srcclock = peer; 199 pp->io.datalen = 0; 200 pp->io.fd = fd; 201 if (!io_addclock(&pp->io)) { 202 close(fd); 203 pp->io.fd = -1; 204 free(up); 205 return (0); 206 } 207 pp->unitptr = up; 208 209 /* 210 * Initialize miscellaneous variables 211 */ 212 peer->precision = PRECISION; 213 pp->clockdesc = DESCRIPTION; 214 memcpy((char *)&pp->refid, REFID, 4); 215 216 up->assert = 1; 217 up->hardpps = 0; 218 /* 219 * Start the PPSAPI interface if it is there. Default to use 220 * the assert edge and do not enable the kernel hardpps. 221 */ 222 if (time_pps_create(fd, &up->pps_handle) < 0) { 223 up->pps_handle = 0; 224 msyslog(LOG_ERR, 225 "refclock_jupiter: time_pps_create failed: %m"); 226 } 227 else if (!jupiter_ppsapi(up)) 228 goto clean_up; 229 230 /* Ensure the receiver is properly configured */ 231 if (!jupiter_config(up)) 232 goto clean_up; 233 234 jupiter_pps(up); /* get current PPS state */ 235 return (1); 236 237clean_up: 238 jupiter_shutdown(unit, peer); 239 pp->unitptr = 0; 240 return (0); 241} 242 243/* 244 * jupiter_shutdown - shut down the clock 245 */ 246static void 247jupiter_shutdown(int unit, struct peer *peer) 248{ 249 struct refclockproc * const pp = peer->procptr; 250 struct instance * const up = pp->unitptr; 251 252 if (!up) 253 return; 254 255 if (up->pps_handle) { 256 time_pps_destroy(up->pps_handle); 257 up->pps_handle = 0; 258 } 259 260 if (pp->io.fd != -1) 261 io_closeclock(&pp->io); 262 free(up); 263} 264 265/* 266 * jupiter_config - Configure the receiver 267 */ 268static int 269jupiter_config(struct instance * const up) 270{ 271 jupiter_debug(up->peer, __func__, "init receiver"); 272 273 /* 274 * Initialize the unit variables 275 */ 276 up->sloppyclockflag = up->peer->procptr->sloppyclockflag; 277 up->moving = !!(up->sloppyclockflag & CLK_FLAG2); 278 if (up->moving) 279 jupiter_debug(up->peer, __func__, "mobile platform"); 280 281 ZERO(up->rcv_next); 282 ZERO(up->ref_next); 283 ZERO(up->piv_next); 284 up->ssize = 0; 285 286 /* Stop outputting all messages */ 287 jupiter_canmsg(up, JUPITER_ALL); 288 289 /* Request the receiver id so we can syslog the firmware version */ 290 jupiter_reqonemsg(up, JUPITER_O_ID); 291 292 /* Flag that this the id was requested (so we don't get called again) */ 293 up->wantid = 1; 294 295 /* Request perodic time mark pulse messages */ 296 jupiter_reqmsg(up, JUPITER_O_PULSE, 1); 297 298 /* Request perodic geodetic position status */ 299 jupiter_reqmsg(up, JUPITER_O_GPOS, 1); 300 301 /* Set application platform type */ 302 if (up->moving) 303 jupiter_platform(up, JUPITER_I_PLAT_MED); 304 else 305 jupiter_platform(up, JUPITER_I_PLAT_LOW); 306 307 return (1); 308} 309 310static void 311jupiter_checkpps( 312 struct refclockproc * const pp, 313 struct instance * const up 314 ) 315{ 316 l_fp tstamp, delta; 317 struct calendar cd; 318 319 if (jupiter_pps(up) || !up->piv_next.weeks) 320 return; 321 322 /* check delay between pulse message and pulse. */ 323 delta = up->rcv_pps; /* set by jupiter_pps() */ 324 L_SUB(&delta, &up->rcv_next); /* recv time pulse message */ 325 if (delta.l_ui != 0 || delta.l_uf >= 0xC0000000) { 326 up->ref_next.weeks = 0; /* consider as consumed... */ 327 return; 328 } 329 330 pp->lastrec = up->rcv_pps; 331 tstamp = ntpfp_from_gpsdatum(&up->ref_next); 332 refclock_process_offset(pp, tstamp, up->rcv_pps, pp->fudgetime1); 333 up->rcvtout = 2; 334 335 gpscal_to_calendar(&cd, &up->ref_next); 336 refclock_save_lcode(pp, ntpcal_iso8601std(NULL, 0, &cd), 337 (size_t)-1); 338 up->ref_next.weeks = 0; /* consumed... */ 339} 340 341/* 342 * jupiter_ticker - process periodic checks 343 */ 344static void 345jupiter_ticker(int unit, struct peer *peer) 346{ 347 struct refclockproc * const pp = peer->procptr; 348 struct instance * const up = pp->unitptr; 349 350 if (!up) 351 return; 352 353 /* check if we can add another sample now */ 354 jupiter_checkpps(pp, up); 355 356 /* check the pivot update cycle */ 357 if (up->piv_hold && !--up->piv_hold) 358 ZERO(up->piv_next); 359 360 if (up->rcvtout) 361 --up->rcvtout; 362 else if (pp->coderecv != pp->codeproc) 363 refclock_samples_expire(pp, 1); 364} 365 366/* 367 * Initialize PPSAPI 368 */ 369int 370jupiter_ppsapi( 371 struct instance * const up /* unit structure pointer */ 372 ) 373{ 374 int capability; 375 376 if (time_pps_getcap(up->pps_handle, &capability) < 0) { 377 msyslog(LOG_ERR, 378 "refclock_jupiter: time_pps_getcap failed: %m"); 379 return (0); 380 } 381 memset(&up->pps_params, 0, sizeof(pps_params_t)); 382 if (!up->assert) 383 up->pps_params.mode = capability & PPS_CAPTURECLEAR; 384 else 385 up->pps_params.mode = capability & PPS_CAPTUREASSERT; 386 if (!(up->pps_params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 387 msyslog(LOG_ERR, 388 "refclock_jupiter: invalid capture edge %d", 389 up->assert); 390 return (0); 391 } 392 up->pps_params.mode |= PPS_TSFMT_TSPEC; 393 if (time_pps_setparams(up->pps_handle, &up->pps_params) < 0) { 394 msyslog(LOG_ERR, 395 "refclock_jupiter: time_pps_setparams failed: %m"); 396 return (0); 397 } 398 if (up->hardpps) { 399 if (time_pps_kcbind(up->pps_handle, PPS_KC_HARDPPS, 400 up->pps_params.mode & ~PPS_TSFMT_TSPEC, 401 PPS_TSFMT_TSPEC) < 0) { 402 msyslog(LOG_ERR, 403 "refclock_jupiter: time_pps_kcbind failed: %m"); 404 return (0); 405 } 406 hardpps_enable = 1; 407 } 408/* up->peer->precision = PPS_PRECISION; */ 409 410#if DEBUG 411 if (debug) { 412 time_pps_getparams(up->pps_handle, &up->pps_params); 413 jupiter_debug(up->peer, __func__, 414 "pps capability 0x%x version %d mode 0x%x kern %d", 415 capability, up->pps_params.api_version, 416 up->pps_params.mode, up->hardpps); 417 } 418#endif 419 420 return (1); 421} 422 423/* 424 * Get PPSAPI timestamps. 425 * 426 * Return 0 on failure and 1 on success. 427 */ 428static int 429jupiter_pps(struct instance * const up) 430{ 431 pps_info_t pps_info; 432 struct timespec timeout, ts; 433 l_fp tstmp; 434 435 /* 436 * Convert the timespec nanoseconds field to ntp l_fp units. 437 */ 438 if (up->pps_handle == 0) 439 return 1; 440 timeout.tv_sec = 0; 441 timeout.tv_nsec = 0; 442 memcpy(&pps_info, &up->pps_info, sizeof(pps_info_t)); 443 if (time_pps_fetch(up->pps_handle, PPS_TSFMT_TSPEC, &up->pps_info, 444 &timeout) < 0) 445 return 1; 446 if (up->pps_params.mode & PPS_CAPTUREASSERT) { 447 if (pps_info.assert_sequence == 448 up->pps_info.assert_sequence) 449 return 1; 450 ts = up->pps_info.assert_timestamp; 451 } else if (up->pps_params.mode & PPS_CAPTURECLEAR) { 452 if (pps_info.clear_sequence == 453 up->pps_info.clear_sequence) 454 return 1; 455 ts = up->pps_info.clear_timestamp; 456 } else { 457 return 1; 458 } 459 460 tstmp = tspec_stamp_to_lfp(ts); 461 if (L_ISEQU(&tstmp, &up->rcv_pps)) 462 return 1; 463 464 up->rcv_pps = tstmp; 465 return 0; 466} 467 468/* 469 * jupiter_poll - jupiter watchdog routine 470 */ 471static void 472jupiter_poll(int unit, struct peer *peer) 473{ 474 struct refclockproc * const pp = peer->procptr; 475 struct instance * const up = pp->unitptr; 476 477 pp->polls++; 478 479 /* 480 * If we have new samples since last poll, everything is fine. 481 * if not, blarb loudly. 482 */ 483 if (pp->coderecv != pp->codeproc) { 484 refclock_receive(peer); 485 refclock_report(peer, CEVNT_NOMINAL); 486 } else { 487 refclock_report(peer, CEVNT_TIMEOUT); 488 489 /* Request the receiver id to trigger a reconfig */ 490 jupiter_reqonemsg(up, JUPITER_O_ID); 491 up->wantid = 0; 492 } 493} 494 495/* 496 * jupiter_control - fudge control 497 */ 498static void 499jupiter_control( 500 int unit, /* unit (not used) */ 501 const struct refclockstat *in, /* input parameters (not used) */ 502 struct refclockstat *out, /* output parameters (not used) */ 503 struct peer *peer /* peer structure pointer */ 504 ) 505{ 506 struct refclockproc * const pp = peer->procptr; 507 struct instance * const up = pp->unitptr; 508 509 u_char sloppyclockflag; 510 511 up->assert = !(pp->sloppyclockflag & CLK_FLAG3); 512 jupiter_ppsapi(up); 513 514 sloppyclockflag = up->sloppyclockflag; 515 up->sloppyclockflag = pp->sloppyclockflag; 516 if ((up->sloppyclockflag & CLK_FLAG2) != 517 (sloppyclockflag & CLK_FLAG2)) { 518 jupiter_debug(peer, __func__, 519 "mode switch: reset receiver"); 520 jupiter_config(up); 521 return; 522 } 523} 524 525/* 526 * jupiter_receive - receive gps data 527 * Gag me! 528 */ 529static void 530jupiter_receive(struct recvbuf * const rbufp) 531{ 532 struct peer * const peer = rbufp->recv_peer; 533 struct refclockproc * const pp = peer->procptr; 534 struct instance * const up = pp->unitptr; 535 536 size_t bpcnt; 537 int cc, size; 538 const char *cp; 539 u_char *bp; 540 u_short *sp; 541 struct jid *ip; 542 struct jheader *hp; 543 544 /* Initialize pointers and read the timecode and timestamp */ 545 bp = (u_char *)rbufp->recv_buffer; 546 bpcnt = rbufp->recv_length; 547 548 /* This shouldn't happen */ 549 if (bpcnt > sizeof(up->sbuf) - up->ssize) 550 bpcnt = sizeof(up->sbuf) - up->ssize; 551 552 /* Append to input buffer */ 553 memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); 554 up->ssize += bpcnt; 555 556 /* While there's at least a header and we parse an intact message */ 557 while (up->ssize > (int)sizeof(*hp) && (cc = jupiter_recv(up)) > 0) { 558 hp = (struct jheader *)up->sbuf; 559 sp = (u_short *)(hp + 1); 560 size = cc - sizeof(*hp); 561 switch (getshort(hp->id)) { 562 563 case JUPITER_O_PULSE: 564 /* first see if we can push another sample: */ 565 jupiter_checkpps(pp, up); 566 567 if (size != sizeof(struct jpulse)) { 568 jupiter_debug(peer, __func__, 569 "pulse: len %d != %u", 570 size, (int)sizeof(struct jpulse)); 571 refclock_report(peer, CEVNT_BADREPLY); 572 break; 573 } 574 575 /* Parse timecode (even when there's no pps) 576 * 577 * There appears to be a firmware bug related to 578 * the pulse message; in addition to the one per 579 * second messages, we get an extra pulse 580 * message once an hour (on the anniversary of 581 * the cold start). It seems to come 200 ms 582 * after the one requested. 583 * 584 * But since we feed samples only when a new PPS 585 * pulse is found we can simply ignore that and 586 * aggregate/update any existing timing message. 587 */ 588 if ((cp = jupiter_parse_t(up, sp, rbufp->recv_time)) != NULL) { 589 jupiter_debug(peer, __func__, 590 "pulse: %s", cp); 591 } 592 break; 593 594 case JUPITER_O_GPOS: 595 if (size != sizeof(struct jgpos)) { 596 jupiter_debug(peer, __func__, 597 "gpos: len %d != %u", 598 size, (int)sizeof(struct jgpos)); 599 refclock_report(peer, CEVNT_BADREPLY); 600 break; 601 } 602 603 if ((cp = jupiter_parse_gpos(up, sp)) != NULL) { 604 jupiter_debug(peer, __func__, 605 "gpos: %s", cp); 606 break; 607 } 608 break; 609 610 case JUPITER_O_ID: 611 if (size != sizeof(struct jid)) { 612 jupiter_debug(peer, __func__, 613 "id: len %d != %u", 614 size, (int)sizeof(struct jid)); 615 refclock_report(peer, CEVNT_BADREPLY); 616 break; 617 } 618 /* 619 * If we got this message because the Jupiter 620 * just powered instance, it needs to be reconfigured. 621 */ 622 ip = (struct jid *)sp; 623 jupiter_debug(peer, __func__, 624 "%s chan ver %s, %s (%s)", 625 ip->chans, ip->vers, ip->date, ip->opts); 626 msyslog(LOG_DEBUG, 627 "jupiter_receive: %s chan ver %s, %s (%s)", 628 ip->chans, ip->vers, ip->date, ip->opts); 629 if (up->wantid) 630 up->wantid = 0; 631 else { 632 jupiter_debug(peer, __func__, "reset receiver"); 633 jupiter_config(up); 634 /* 635 * Restore since jupiter_config() just 636 * zeroed it 637 */ 638 up->ssize = cc; 639 } 640 break; 641 642 default: 643 jupiter_debug(peer, __func__, "unknown message id %d", 644 getshort(hp->id)); 645 break; 646 } 647 up->ssize -= cc; 648 if (up->ssize < 0) { 649 fprintf(stderr, "jupiter_recv: negative ssize!\n"); 650 abort(); 651 } else if (up->ssize > 0) 652 memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); 653 } 654} 655 656static const char * 657jupiter_parse_t( 658 struct instance * const up, 659 u_short * sp, 660 l_fp rcvtime 661 ) 662{ 663 struct jpulse *jp; 664 u_int32 sweek; 665 u_short flags; 666 l_fp fofs; 667 668 jp = (struct jpulse *)sp; 669 flags = getshort(jp->flags); 670 671 /* Toss if not designated "valid" by the gps. 672 * !!NOTE!! do *not* kill data received so far! 673 */ 674 if ((flags & JUPITER_O_PULSE_VALID) == 0) { 675 refclock_report(up->peer, CEVNT_BADTIME); 676 return ("time mark not valid"); 677 } 678 679 up->rcv_next = rcvtime; /* remember when this happened */ 680 681 /* The timecode is presented as seconds into the current GPS week */ 682 sweek = DS2UI(jp->sweek) % WEEKSECS; 683 /* check if we have to apply the UTC offset ourselves */ 684 if ((flags & JUPITER_O_PULSE_UTC) == 0) { 685 struct timespec tofs; 686 tofs.tv_sec = getshort(jp->offs); 687 tofs.tv_nsec = DS2I(jp->offns); 688 fofs = tspec_intv_to_lfp(tofs); 689 L_NEG(&fofs); 690 } else { 691 ZERO(fofs); 692 } 693 694 /* 695 * If we don't know the current GPS week, calculate it from the 696 * current time. (It's too bad they didn't include this 697 * important value in the pulse message). 698 * 699 * So we pick the pivot value from the other messages like gpos 700 * or chan if we can. Of course, the PULSE message can be in UTC 701 * or GPS time scale, and the other messages are simply always 702 * GPS time. 703 * 704 * But as long as the difference between the time stamps is less 705 * than a half week, the unfolding of a week time is unambigeous 706 * and well suited for the problem we have here. And we won't 707 * see *that* many leap seconds, ever. 708 */ 709 if (up->piv_next.weeks) { 710 up->ref_next = gpscal_from_weektime2( 711 sweek, fofs, &up->piv_next); 712 up->piv_next = up->ref_next; 713 } else { 714 up->ref_next = gpscal_from_weektime1( 715 sweek, fofs, rcvtime); 716 } 717 718 719 720 return (NULL); 721} 722 723static const char * 724jupiter_parse_gpos( 725 struct instance * const up, 726 u_short * sp 727 ) 728{ 729 struct jgpos *jg; 730 struct calendar tref; 731 char *cp; 732 struct timespec tofs; 733 uint16_t raw_week; 734 uint32_t raw_secs; 735 736 jg = (struct jgpos *)sp; 737 738 if (jg->navval != 0) { 739 /* 740 * Solution not valid. Use caution and refuse 741 * to determine GPS week from this message. 742 */ 743 return ("Navigation solution not valid"); 744 } 745 746 raw_week = getshort(jg->gweek); 747 raw_secs = DS2UI(jg->sweek); 748 tofs.tv_sec = 0; 749 tofs.tv_nsec = DS2UI(jg->nsweek); 750 up->piv_next = gpscal_from_gpsweek(raw_week, raw_secs, 751 tspec_intv_to_lfp(tofs)); 752 up->piv_hold = 60; 753 754 gpscal_to_calendar(&tref, &up->piv_next); 755 cp = ntpcal_iso8601std(NULL, 0, &tref); 756 jupiter_debug(up->peer, __func__, 757 "GPS %s (gweek/sweek %hu/%u)", 758 cp, (unsigned short)raw_week, (unsigned int)raw_secs); 759 return (NULL); 760} 761 762/* 763 * jupiter_debug - print debug messages 764 */ 765static void 766jupiter_debug( 767 struct peer * peer, 768 const char * function, 769 const char * fmt, 770 ... 771 ) 772{ 773 char buffer[200]; 774 va_list ap; 775 776 va_start(ap, fmt); 777 /* 778 * Print debug message to stdout 779 * In the future, we may want to get get more creative... 780 */ 781 mvsnprintf(buffer, sizeof(buffer), fmt, ap); 782 record_clock_stats(&peer->srcadr, buffer); 783#ifdef DEBUG 784 if (debug) { 785 printf("%s: %s\n", function, buffer); 786 fflush(stdout); 787 } 788#endif 789 790 va_end(ap); 791} 792 793/* Checksum and transmit a message to the Jupiter */ 794static char * 795jupiter_send( 796 struct instance * const up, 797 struct jheader * hp 798 ) 799{ 800 u_int len, size; 801 ssize_t cc; 802 u_short *sp; 803 static char errstr[132]; 804 805 size = sizeof(*hp); 806 hp->hsum = putshort(jupiter_cksum((u_short *)hp, 807 (size / sizeof(u_short)) - 1)); 808 len = getshort(hp->len); 809 if (len > 0) { 810 sp = (u_short *)(hp + 1); 811 sp[len] = putshort(jupiter_cksum(sp, len)); 812 size += (len + 1) * sizeof(u_short); 813 } 814 815 if ((cc = write(up->peer->procptr->io.fd, (char *)hp, size)) < 0) { 816 msnprintf(errstr, sizeof(errstr), "write: %m"); 817 return (errstr); 818 } else if (cc != (int)size) { 819 snprintf(errstr, sizeof(errstr), "short write (%zd != %u)", cc, size); 820 return (errstr); 821 } 822 return (NULL); 823} 824 825/* Request periodic message output */ 826static struct { 827 struct jheader jheader; 828 struct jrequest jrequest; 829} reqmsg = { 830 { putshort(JUPITER_SYNC), 0, 831 putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 832 0, JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 833 JUPITER_FLAG_CONN | JUPITER_FLAG_LOG, 0 }, 834 { 0, 0, 0, 0 } 835}; 836 837/* An interval of zero means to output on trigger */ 838static void 839jupiter_reqmsg( 840 struct instance * const up, 841 u_int id, 842 u_int interval 843 ) 844{ 845 struct jheader *hp; 846 struct jrequest *rp; 847 char *cp; 848 849 hp = &reqmsg.jheader; 850 hp->id = putshort(id); 851 rp = &reqmsg.jrequest; 852 rp->trigger = putshort(interval == 0); 853 rp->interval = putshort(interval); 854 if ((cp = jupiter_send(up, hp)) != NULL) 855 jupiter_debug(up->peer, __func__, "%u: %s", id, cp); 856} 857 858/* Cancel periodic message output */ 859static struct jheader canmsg = { 860 putshort(JUPITER_SYNC), 0, 0, 0, 861 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC, 862 0 863}; 864 865static void 866jupiter_canmsg( 867 struct instance * const up, 868 u_int id 869 ) 870{ 871 struct jheader *hp; 872 char *cp; 873 874 hp = &canmsg; 875 hp->id = putshort(id); 876 if ((cp = jupiter_send(up, hp)) != NULL) 877 jupiter_debug(up->peer, __func__, "%u: %s", id, cp); 878} 879 880/* Request a single message output */ 881static struct jheader reqonemsg = { 882 putshort(JUPITER_SYNC), 0, 0, 0, 883 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY, 884 0 885}; 886 887static void 888jupiter_reqonemsg( 889 struct instance * const up, 890 u_int id 891 ) 892{ 893 struct jheader *hp; 894 char *cp; 895 896 hp = &reqonemsg; 897 hp->id = putshort(id); 898 if ((cp = jupiter_send(up, hp)) != NULL) 899 jupiter_debug(up->peer, __func__, "%u: %s", id, cp); 900} 901 902/* Set the platform dynamics */ 903static struct { 904 struct jheader jheader; 905 struct jplat jplat; 906} platmsg = { 907 { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 908 putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 909 JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK, 0 }, 910 { 0, 0, 0 } 911}; 912 913static void 914jupiter_platform( 915 struct instance * const up, 916 u_int platform 917 ) 918{ 919 struct jheader *hp; 920 struct jplat *pp; 921 char *cp; 922 923 hp = &platmsg.jheader; 924 pp = &platmsg.jplat; 925 pp->platform = putshort(platform); 926 if ((cp = jupiter_send(up, hp)) != NULL) 927 jupiter_debug(up->peer, __func__, "%u: %s", platform, cp); 928} 929 930/* Checksum "len" shorts */ 931static u_short 932jupiter_cksum(u_short *sp, u_int len) 933{ 934 u_short sum, x; 935 936 sum = 0; 937 while (len-- > 0) { 938 x = *sp++; 939 sum += getshort(x); 940 } 941 return (~sum + 1); 942} 943 944/* Return the size of the next message (or zero if we don't have it all yet) */ 945static int 946jupiter_recv( 947 struct instance * const up 948 ) 949{ 950 int n, len, size, cc; 951 struct jheader *hp; 952 u_char *bp; 953 u_short *sp; 954 955 /* Must have at least a header's worth */ 956 cc = sizeof(*hp); 957 size = up->ssize; 958 if (size < cc) 959 return (0); 960 961 /* Search for the sync short if missing */ 962 sp = up->sbuf; 963 hp = (struct jheader *)sp; 964 if (getshort(hp->sync) != JUPITER_SYNC) { 965 /* Wasn't at the front, sync up */ 966 jupiter_debug(up->peer, __func__, "syncing"); 967 bp = (u_char *)sp; 968 n = size; 969 while (n >= 2) { 970 if (bp[0] != (JUPITER_SYNC & 0xff)) { 971 /* 972 jupiter_debug(up->peer, __func__, 973 "{0x%x}", bp[0]); 974 */ 975 ++bp; 976 --n; 977 continue; 978 } 979 if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 980 break; 981 /* 982 jupiter_debug(up->peer, __func__, 983 "{0x%x 0x%x}", bp[0], bp[1]); 984 */ 985 bp += 2; 986 n -= 2; 987 } 988 /* 989 jupiter_debug(up->peer, __func__, "\n"); 990 */ 991 /* Shuffle data to front of input buffer */ 992 if (n > 0) 993 memcpy(sp, bp, n); 994 size = n; 995 up->ssize = size; 996 if (size < cc || hp->sync != JUPITER_SYNC) 997 return (0); 998 } 999 1000 if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1001 getshort(hp->hsum)) { 1002 jupiter_debug(up->peer, __func__, "bad header checksum!"); 1003 /* This is drastic but checksum errors should be rare */ 1004 up->ssize = 0; 1005 return (0); 1006 } 1007 1008 /* Check for a payload */ 1009 len = getshort(hp->len); 1010 if (len > 0) { 1011 n = (len + 1) * sizeof(u_short); 1012 /* Not enough data yet */ 1013 if (size < cc + n) 1014 return (0); 1015 1016 /* Check payload checksum */ 1017 sp = (u_short *)(hp + 1); 1018 if (jupiter_cksum(sp, len) != getshort(sp[len])) { 1019 jupiter_debug(up->peer, 1020 __func__, "bad payload checksum!"); 1021 /* This is drastic but checksum errors should be rare */ 1022 up->ssize = 0; 1023 return (0); 1024 } 1025 cc += n; 1026 } 1027 return (cc); 1028} 1029 1030#else /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1031int refclock_jupiter_bs; 1032#endif /* not (REFCLOCK && CLOCK_JUPITER && HAVE_PPSAPI) */ 1033