refclock_jupiter.c revision 54359
1/* 2 * Copyright (c) 1997, 1998 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(PPS) 39 40#include <stdio.h> 41#include <ctype.h> 42#include <sys/time.h> 43 44#include "ntpd.h" 45#include "ntp_io.h" 46#include "ntp_refclock.h" 47#include "ntp_unixtime.h" 48#include "ntp_stdlib.h" 49#include "ntp_calendar.h" 50 51#include "jupiter.h" 52 53#include <sys/ppsclock.h> 54 55#ifdef XNTP_BIG_ENDIAN 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) (s) 60#define putshort(s) (s) 61#endif 62 63/* XXX */ 64#ifdef sun 65char *strerror(int); 66#endif 67 68/* 69 * This driver supports the Rockwell Jupiter GPS Receiver board 70 * adapted to precision timing applications. It requires the 71 * ppsclock line discipline or streams module described in the 72 * Line Disciplines and Streams Drivers page. It also requires a 73 * gadget box and 1-PPS level converter, such as described in the 74 * Pulse-per-second (PPS) Signal Interfacing page. 75 * 76 * It may work (with minor modifications) with other Rockwell GPS 77 * receivers such as the CityTracker. 78 */ 79 80/* 81 * GPS Definitions 82 */ 83#define DEVICE "/dev/gps%d" /* device name and unit */ 84#define SPEED232 B9600 /* baud */ 85 86/* 87 * The number of raw samples which we acquire to derive a single estimate. 88 * NSAMPLES ideally should not exceed the default poll interval 64. 89 * NKEEP must be a power of 2 to simplify the averaging process. 90 */ 91#define NSAMPLES 64 92#define NKEEP 8 93#define REFCLOCKMAXDISPERSE .25 /* max sample dispersion */ 94 95/* 96 * Radio interface parameters 97 */ 98#define PRECISION (-18) /* precision assumed (about 4 us) */ 99#define REFID "GPS\0" /* reference id */ 100#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ 101#define DEFFUDGETIME 0 /* default fudge time (ms) */ 102 103/* Unix timestamp for the GPS epoch: January 6, 1980 */ 104#define GPS_EPOCH 315964800 105 106/* Double short to unsigned int */ 107#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 108 109/* Double short to signed int */ 110#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 111 112/* One week's worth of seconds */ 113#define WEEKSECS (7 * 24 * 60 * 60) 114 115/* 116 * Jupiter unit control structure. 117 */ 118struct jupiterunit { 119 u_int pollcnt; /* poll message counter */ 120 u_int polled; /* Hand in a time sample? */ 121 u_int lastserial; /* last pps serial number */ 122 struct ppsclockev ppsev; /* PPS control structure */ 123 u_int gweek; /* current GPS week number */ 124 u_int32 lastsweek; /* last seconds into GPS week */ 125 u_int32 timecode; /* current ntp timecode */ 126 u_int32 stime; /* used to detect firmware bug */ 127 int wantid; /* don't reconfig on channel id msg */ 128 u_int moving; /* mobile platform? */ 129 u_long sloppyclockflag; /* fudge flags */ 130 u_int known; /* position known yet? */ 131 int coderecv; /* total received samples */ 132 int nkeep; /* number of samples to preserve */ 133 int rshift; /* number of rshifts for division */ 134 l_fp filter[NSAMPLES]; /* offset filter */ 135 l_fp lastref; /* last reference timestamp */ 136 u_short sbuf[512]; /* local input buffer */ 137 int ssize; /* space used in sbuf */ 138}; 139 140/* 141 * Function prototypes 142 */ 143static void jupiter_canmsg P((struct peer *, u_int)); 144static u_short jupiter_cksum P((u_short *, u_int)); 145#ifdef QSORT_USES_VOID_P 146 int jupiter_cmpl_fp P((const void *, const void *)); 147#else 148 int jupiter_cmpl_fp P((const l_fp *, const l_fp *)); 149#endif /* not QSORT_USES_VOID_P */ 150static void jupiter_config P((struct peer *)); 151static void jupiter_debug P((struct peer *, char *, ...)) 152 __attribute__ ((format (printf, 2, 3))); 153static char * jupiter_offset P((struct peer *)); 154static char * jupiter_parse_t P((struct peer *, u_short *)); 155static void jupiter_platform P((struct peer *, u_int)); 156static void jupiter_poll P((int, struct peer *)); 157static int jupiter_pps P((struct peer *)); 158static char * jupiter_process P((struct peer *)); 159static int jupiter_recv P((struct peer *)); 160static void jupiter_receive P((register struct recvbuf *rbufp)); 161static void jupiter_reqmsg P((struct peer *, u_int, u_int)); 162static void jupiter_reqonemsg P((struct peer *, u_int)); 163static char * jupiter_send P((struct peer *, struct jheader *)); 164static void jupiter_shutdown P((int, struct peer *)); 165static int jupiter_start P((int, struct peer *)); 166static int jupiter_ttyinit P((struct peer *, int)); 167 168/* 169 * Transfer vector 170 */ 171struct refclock refclock_jupiter = { 172 jupiter_start, /* start up driver */ 173 jupiter_shutdown, /* shut down driver */ 174 jupiter_poll, /* transmit poll message */ 175 noentry, /* (clock control) */ 176 noentry, /* (clock init) */ 177 noentry, /* (clock buginfo) */ 178 NOFLAGS /* not used */ 179}; 180 181/* 182 * jupiter_start - open the devices and initialize data for processing 183 */ 184static int 185jupiter_start( 186 register int unit, 187 register struct peer *peer 188 ) 189{ 190 struct refclockproc *pp; 191 register struct jupiterunit *up; 192 register int fd; 193 char gpsdev[20]; 194 195 /* 196 * Open serial port 197 */ 198 (void)sprintf(gpsdev, DEVICE, unit); 199 fd = open(gpsdev, O_RDWR 200#ifdef O_NONBLOCK 201 | O_NONBLOCK 202#endif 203 , 0); 204 if (fd < 0) { 205 jupiter_debug(peer, "jupiter_start: open %s: %s\n", 206 gpsdev, strerror(errno)); 207 return (0); 208 } 209 if (!jupiter_ttyinit(peer, fd)) 210 return (0); 211 212 /* Allocate unit structure */ 213 if ((up = (struct jupiterunit *) 214 emalloc(sizeof(struct jupiterunit))) == NULL) { 215 (void) close(fd); 216 return (0); 217 } 218 memset((char *)up, 0, sizeof(struct jupiterunit)); 219 pp = peer->procptr; 220 pp->io.clock_recv = jupiter_receive; 221 pp->io.srcclock = (caddr_t)peer; 222 pp->io.datalen = 0; 223 pp->io.fd = fd; 224 if (!io_addclock(&pp->io)) { 225 (void) close(fd); 226 free(up); 227 return (0); 228 } 229 pp->unitptr = (caddr_t)up; 230 231 /* 232 * Initialize miscellaneous variables 233 */ 234 peer->precision = PRECISION; 235 pp->clockdesc = DESCRIPTION; 236 memcpy((char *)&pp->refid, REFID, 4); 237 238 239 /* Ensure the receiver is properly configured */ 240 jupiter_config(peer); 241 242 /* Turn on pulse gathering by requesting the first sample */ 243 if (ioctl(fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { 244 jupiter_debug(peer, "jupiter_ttyinit: CIOGETEV: %s\n", 245 strerror(errno)); 246 (void) close(fd); 247 free(up); 248 return (0); 249 } 250 up->lastserial = up->ppsev.serial; 251 memset(&up->ppsev, 0, sizeof(up->ppsev)); 252 return (1); 253} 254 255/* 256 * jupiter_shutdown - shut down the clock 257 */ 258static void 259jupiter_shutdown(register int unit, register struct peer *peer) 260{ 261 register struct jupiterunit *up; 262 struct refclockproc *pp; 263 264 pp = peer->procptr; 265 up = (struct jupiterunit *)pp->unitptr; 266 io_closeclock(&pp->io); 267 free(up); 268} 269 270/* 271 * jupiter_config - Configure the receiver 272 */ 273static void 274jupiter_config(register struct peer *peer) 275{ 276 register int i; 277 register struct jupiterunit *up; 278 register struct refclockproc *pp; 279 280 pp = peer->procptr; 281 up = (struct jupiterunit *)pp->unitptr; 282 283 /* 284 * Initialize the unit variables 285 * 286 * STRANGE BEHAVIOUR WARNING: The fudge flags are not available 287 * at the time jupiter_start is called. These are set later, 288 * and so the code must be prepared to handle changing flags. 289 */ 290 up->sloppyclockflag = pp->sloppyclockflag; 291 if (pp->sloppyclockflag & CLK_FLAG2) { 292 up->moving = 1; /* Receiver on mobile platform */ 293 msyslog(LOG_DEBUG, "jupiter_config: mobile platform"); 294 } else { 295 up->moving = 0; /* Static Installation */ 296 } 297 298 /* XXX fludge flags don't make the trip from the config to here... */ 299#ifdef notdef 300 /* Configure for trailing edge triggers */ 301#ifdef CIOSETTET 302 i = ((pp->sloppyclockflag & CLK_FLAG3) != 0); 303 jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n", 304 pp->sloppyclockflag); 305 if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0) 306 msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i); 307#else 308 if (pp->sloppyclockflag & CLK_FLAG3) 309 msyslog(LOG_DEBUG, "jupiter_configure: \ 310No kernel support for trailing edge trigger"); 311#endif 312#endif 313 314 up->pollcnt = 2; 315 up->polled = 0; 316 up->known = 0; 317 up->gweek = 0; 318 up->lastsweek = 2 * WEEKSECS; 319 up->timecode = 0; 320 up->stime = 0; 321 up->ssize = 0; 322 up->coderecv = 0; 323 up->nkeep = NKEEP; 324 if (up->nkeep > NSAMPLES) 325 up->nkeep = NSAMPLES; 326 if (up->nkeep >= 1) 327 up->rshift = 0; 328 if (up->nkeep >= 2) 329 up->rshift = 1; 330 if (up->nkeep >= 4) 331 up->rshift = 2; 332 if (up->nkeep >= 8) 333 up->rshift = 3; 334 if (up->nkeep >= 16) 335 up->rshift = 4; 336 if (up->nkeep >= 32) 337 up->rshift = 5; 338 if (up->nkeep >= 64) 339 up->rshift = 6; 340 up->nkeep = 1; 341 i = up->rshift; 342 while (i > 0) { 343 up->nkeep *= 2; 344 i--; 345 } 346 347 /* Stop outputting all messages */ 348 jupiter_canmsg(peer, JUPITER_ALL); 349 350 /* Request the receiver id so we can syslog the firmware version */ 351 jupiter_reqonemsg(peer, JUPITER_O_ID); 352 353 /* Flag that this the id was requested (so we don't get called again) */ 354 up->wantid = 1; 355 356 /* Request perodic time mark pulse messages */ 357 jupiter_reqmsg(peer, JUPITER_O_PULSE, 1); 358 359 /* Set application platform type */ 360 if (up->moving) 361 jupiter_platform(peer, JUPITER_I_PLAT_MED); 362 else 363 jupiter_platform(peer, JUPITER_I_PLAT_LOW); 364} 365 366/* 367 * jupiter_poll - jupiter watchdog routine 368 */ 369static void 370jupiter_poll(register int unit, register struct peer *peer) 371{ 372 register struct jupiterunit *up; 373 register struct refclockproc *pp; 374 375 pp = peer->procptr; 376 up = (struct jupiterunit *)pp->unitptr; 377 378 /* 379 * You don't need to poll this clock. It puts out timecodes 380 * once per second. If asked for a timestamp, take note. 381 * The next time a timecode comes in, it will be fed back. 382 */ 383 384 /* 385 * If we haven't had a response in a while, reset the receiver. 386 */ 387 if (up->pollcnt > 0) { 388 up->pollcnt--; 389 } else { 390 refclock_report(peer, CEVNT_TIMEOUT); 391 392 /* Request the receiver id to trigger a reconfig */ 393 jupiter_reqonemsg(peer, JUPITER_O_ID); 394 up->wantid = 0; 395 } 396 397 /* 398 * polled every 64 seconds. Ask jupiter_receive to hand in 399 * a timestamp. 400 */ 401 up->polled = 1; 402 pp->polls++; 403} 404 405/* 406 * jupiter_receive - receive gps data 407 * Gag me! 408 */ 409static void 410jupiter_receive(register struct recvbuf *rbufp) 411{ 412 register int bpcnt, cc, size, ppsret; 413 register u_int32 last_timecode, laststime; 414 register char *cp; 415 register u_char *bp; 416 register u_short *sp; 417 register u_long sloppyclockflag; 418 register struct jupiterunit *up; 419 register struct jid *ip; 420 register struct jheader *hp; 421 register struct refclockproc *pp; 422 register struct peer *peer; 423 424 /* Initialize pointers and read the timecode and timestamp */ 425 peer = (struct peer *)rbufp->recv_srcclock; 426 pp = peer->procptr; 427 up = (struct jupiterunit *)pp->unitptr; 428 429 /* 430 * If operating mode has been changed, then reinitialize the receiver 431 * before doing anything else. 432 */ 433/* XXX Sloppy clock flags are broken!! */ 434 sloppyclockflag = up->sloppyclockflag; 435 up->sloppyclockflag = pp->sloppyclockflag; 436 if ((pp->sloppyclockflag & CLK_FLAG2) != 437 (sloppyclockflag & CLK_FLAG2)) { 438 jupiter_debug(peer, 439 "jupiter_receive: mode switch: reset receiver\n"); 440 jupiter_config(peer); 441 return; 442 } 443 444 up->pollcnt = 2; 445 446 bp = (u_char *)rbufp->recv_buffer; 447 bpcnt = rbufp->recv_length; 448 449 /* This shouldn't happen */ 450 if (bpcnt > sizeof(up->sbuf) - up->ssize) 451 bpcnt = sizeof(up->sbuf) - up->ssize; 452 453 /* Append to input buffer */ 454 memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); 455 up->ssize += bpcnt; 456 457 /* While there's at least a header and we parse a intact message */ 458 while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) { 459 hp = (struct jheader *)up->sbuf; 460 sp = (u_short *)(hp + 1); 461 size = cc - sizeof(*hp); 462 switch (getshort(hp->id)) { 463 464 case JUPITER_O_PULSE: 465 if (size != sizeof(struct jpulse)) { 466 jupiter_debug(peer, 467 "jupiter_receive: pulse: len %d != %u\n", 468 size, (int)sizeof(struct jpulse)); 469 refclock_report(peer, CEVNT_BADREPLY); 470 break; 471 } 472 473 /* 474 * There appears to be a firmware bug related 475 * to the pulse message; in addition to the one 476 * per second messages, we get an extra pulse 477 * message once an hour (on the anniversary of 478 * the cold start). It seems to come 200 ms 479 * after the one requested. So if we've seen a 480 * pulse message in the last 210 ms, we skip 481 * this one. 482 */ 483 laststime = up->stime; 484 up->stime = DS2UI(((struct jpulse *)sp)->stime); 485 if (laststime != 0 && up->stime - laststime <= 21) { 486 jupiter_debug(peer, "jupiter_receive: \ 487avoided firmware bug (stime %.2f, laststime %.2f)\n", 488 (double)up->stime * 0.01, (double)laststime * 0.01); 489 break; 490 } 491 492 /* Retrieve pps timestamp */ 493 ppsret = jupiter_pps(peer); 494 495 /* Parse timecode (even when there's no pps) */ 496 last_timecode = up->timecode; 497 if ((cp = jupiter_parse_t(peer, sp)) != NULL) { 498 jupiter_debug(peer, 499 "jupiter_receive: pulse: %s\n", cp); 500 break; 501 } 502 503 /* Bail if we didn't get a pps timestamp */ 504 if (ppsret) 505 break; 506 507 /* Bail if we don't have the last timecode yet */ 508 if (last_timecode == 0) 509 break; 510 511 /* Add the new sample to a median filter */ 512 if ((cp = jupiter_offset(peer)) != NULL) { 513 jupiter_debug(peer, 514 "jupiter_receive: offset: %s\n", cp); 515 refclock_report(peer, CEVNT_BADTIME); 516 break; 517 } 518 519 /* 520 * The clock will blurt a timecode every second 521 * but we only want one when polled. If we 522 * havn't been polled, bail out. 523 */ 524 if (!up->polled) 525 break; 526 527 /* 528 * It's a live one! Remember this time. 529 */ 530 pp->lasttime = current_time; 531 532 /* 533 * Determine the reference clock offset and 534 * dispersion. NKEEP of NSAMPLE offsets are 535 * passed through a median filter. 536 * Save the (filtered) offset and dispersion in 537 * pp->offset and pp->disp. 538 */ 539 if ((cp = jupiter_process(peer)) != NULL) { 540 jupiter_debug(peer, 541 "jupiter_receive: process: %s\n", cp); 542 refclock_report(peer, CEVNT_BADTIME); 543 break; 544 } 545 /* 546 * Return offset and dispersion to control 547 * module. We use lastrec as both the reference 548 * time and receive time in order to avoid 549 * being cute, like setting the reference time 550 * later than the receive time, which may cause 551 * a paranoid protocol module to chuck out the 552 * data. 553 */ 554 jupiter_debug(peer, 555 "jupiter_receive: process time: \ 556%4d-%03d %02d:%02d:%02d at %s, %s\n", 557 pp->year, pp->day, 558 pp->hour, pp->minute, pp->second, 559 prettydate(&pp->lastrec), lfptoa(&pp->offset, 6)); 560 561 refclock_receive(peer); 562 563 /* 564 * We have succeeded in answering the poll. 565 * Turn off the flag and return 566 */ 567 up->polled = 0; 568 break; 569 570 case JUPITER_O_ID: 571 if (size != sizeof(struct jid)) { 572 jupiter_debug(peer, 573 "jupiter_receive: id: len %d != %u\n", 574 size, (int)sizeof(struct jid)); 575 refclock_report(peer, CEVNT_BADREPLY); 576 break; 577 } 578 /* 579 * If we got this message because the Jupiter 580 * just powered up, it needs to be reconfigured. 581 */ 582 ip = (struct jid *)sp; 583 jupiter_debug(peer, 584 "jupiter_receive: >> %s chan ver %s, %s (%s)\n", 585 ip->chans, ip->vers, ip->date, ip->opts); 586 msyslog(LOG_DEBUG, 587 "jupiter_receive: %s chan ver %s, %s (%s)\n", 588 ip->chans, ip->vers, ip->date, ip->opts); 589 if (up->wantid) 590 up->wantid = 0; 591 else { 592 jupiter_debug(peer, 593 "jupiter_receive: reset receiver\n"); 594 jupiter_config(peer); 595 /* Rese since jupiter_config() just zeroed it */ 596 up->ssize = cc; 597 } 598 break; 599 600 default: 601 jupiter_debug(peer, 602 "jupiter_receive: >> unknown message id %d\n", 603 getshort(hp->id)); 604 break; 605 } 606 up->ssize -= cc; 607 if (up->ssize < 0) { 608 fprintf(stderr, "jupiter_recv: negative ssize!\n"); 609 abort(); 610 } else if (up->ssize > 0) 611 memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); 612 } 613 record_clock_stats(&peer->srcadr, "<timecode is binary>"); 614} 615 616/* 617 * jupiter_offset - Calculate the offset, and add to the rolling filter. 618 */ 619static char * 620jupiter_offset(register struct peer *peer) 621{ 622 register struct jupiterunit *up; 623 register struct refclockproc *pp; 624 register int i; 625 l_fp offset; 626 627 pp = peer->procptr; 628 up = (struct jupiterunit *)pp->unitptr; 629 630 /* 631 * Calculate the offset 632 */ 633 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 634 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) { 635 return ("jupiter_process: clocktime failed"); 636 } 637 if (pp->usec) { 638 TVUTOTSF(pp->usec, offset.l_uf); 639 } else { 640 MSUTOTSF(pp->msec, offset.l_uf); 641 } 642 L_ADD(&offset, &pp->fudgetime1); 643 up->lastref = offset; /* save last reference time */ 644 L_SUB(&offset, &pp->lastrec); /* form true offset */ 645 646 /* 647 * A rolling filter. Initialize first time around. 648 */ 649 i = ((up->coderecv)) % NSAMPLES; 650 651 up->filter[i] = offset; 652 if (up->coderecv == 0) 653 for (i = 1; (u_int) i < NSAMPLES; i++) 654 up->filter[i] = up->filter[0]; 655 up->coderecv++; 656 657 return (NULL); 658} 659 660/* 661 * jupiter_process - process the sample from the clock, 662 * passing it through a median filter and optionally averaging 663 * the samples. Returns offset and dispersion in "up" structure. 664 */ 665static char * 666jupiter_process(register struct peer *peer) 667{ 668 register struct jupiterunit *up; 669 register struct refclockproc *pp; 670 register int i, n; 671 register int j, k; 672 l_fp offset, median, lftmp; 673 u_fp disp; 674 l_fp off[NSAMPLES]; 675 676 pp = peer->procptr; 677 up = (struct jupiterunit *)pp->unitptr; 678 679 /* 680 * Copy the raw offsets and sort into ascending order 681 */ 682 for (i = 0; i < NSAMPLES; i++) 683 off[i] = up->filter[i]; 684 qsort((char *)off, NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); 685 686 /* 687 * Reject the furthest from the median of NSAMPLES samples until 688 * NKEEP samples remain. 689 */ 690 i = 0; 691 n = NSAMPLES; 692 while ((n - i) > up->nkeep) { 693 lftmp = off[n - 1]; 694 median = off[(n + i) / 2]; 695 L_SUB(&lftmp, &median); 696 L_SUB(&median, &off[i]); 697 if (L_ISHIS(&median, &lftmp)) { 698 /* reject low end */ 699 i++; 700 } else { 701 /* reject high end */ 702 n--; 703 } 704 } 705 706 /* 707 * Copy key values to the billboard to measure performance. 708 */ 709 pp->lastref = up->lastref; 710 pp->coderecv = up->coderecv; 711 pp->filter[0] = off[0]; /* smallest offset */ 712 pp->filter[1] = off[NSAMPLES-1]; /* largest offset */ 713 for (j = 2, k = i; k < n; j++, k++) 714 pp->filter[j] = off[k]; /* offsets actually examined */ 715 716 /* 717 * Compute the dispersion based on the difference between the 718 * extremes of the remaining offsets. Add to this the time since 719 * the last clock update, which represents the dispersion 720 * increase with time. We know that NTP_MAXSKEW is 16. If the 721 * sum is greater than the allowed sample dispersion, bail out. 722 * If the loop is unlocked, return the most recent offset; 723 * otherwise, return the median offset. 724 */ 725 lftmp = off[n - 1]; 726 L_SUB(&lftmp, &off[i]); 727 disp = LFPTOFP(&lftmp); 728 if (disp > REFCLOCKMAXDISPERSE) 729 return ("Maximum dispersion exceeded"); 730 731 /* 732 * Now compute the offset estimate. If fudge flag 1 733 * is set, average the remainder, otherwise pick the 734 * median. 735 */ 736 if (pp->sloppyclockflag & CLK_FLAG1) { 737 L_CLR(&lftmp); 738 while (i < n) { 739 L_ADD(&lftmp, &off[i]); 740 i++; 741 } 742 i = up->rshift; 743 while (i > 0) { 744 L_RSHIFT(&lftmp); 745 i--; 746 } 747 offset = lftmp; 748 } else { 749 i = (n + i) / 2; 750 offset = off[i]; 751 } 752 753 /* 754 * The payload: filtered offset and dispersion. 755 */ 756 757 pp->offset = offset; 758 pp->disp = disp; 759 760 return (NULL); 761 762} 763 764/* Compare two l_fp's, used with qsort() */ 765int 766#ifdef QSORT_USES_VOID_P 767jupiter_cmpl_fp(register const void *p1, register const void *p2) 768#else 769jupiter_cmpl_fp(register const l_fp *fp1, register const l_fp *fp2) 770#endif 771{ 772#ifdef QSORT_USES_VOID_P 773 register const l_fp *fp1 = (const l_fp *)p1; 774 register const l_fp *fp2 = (const l_fp *)p2; 775#endif 776 777 if (!L_ISGEQ(fp1, fp2)) 778 return (-1); 779 if (L_ISEQU(fp1, fp2)) 780 return (0); 781 return (1); 782} 783 784static char * 785jupiter_parse_t(register struct peer *peer, register u_short *sp) 786{ 787 register struct refclockproc *pp; 788 register struct jupiterunit *up; 789 register struct tm *tm; 790 register char *cp; 791 register struct jpulse *jp; 792 register struct calendar *jt; 793 register u_int32 sweek; 794 register u_int32 last_timecode; 795 register u_short flags; 796 time_t t; 797 struct calendar cal; 798 799 pp = peer->procptr; 800 up = (struct jupiterunit *)pp->unitptr; 801 jp = (struct jpulse *)sp; 802 803 /* The timecode is presented as seconds into the current GPS week */ 804 sweek = DS2UI(jp->sweek); 805 806 /* 807 * If we don't know the current GPS week, calculate it from the 808 * current time. (It's too bad they didn't include this 809 * important value in the pulse message). We'd like to pick it 810 * up from one of the other messages like gpos or chan but they 811 * don't appear to be synchronous with time keeping and changes 812 * too soon (something like 10 seconds before the new GPS 813 * week). 814 * 815 * If we already know the current GPS week, increment it when 816 * we wrap into a new week. 817 */ 818 if (up->gweek == 0) 819 up->gweek = (time(NULL) - GPS_EPOCH) / WEEKSECS; 820 else if (sweek == 0 && up->lastsweek == WEEKSECS - 1) { 821 ++up->gweek; 822 jupiter_debug(peer, 823 "jupiter_parse_t: NEW gps week %u\n", up->gweek); 824 } 825 826 /* 827 * See if the sweek stayed the same (this happens when there is 828 * no pps pulse). 829 * 830 * Otherwise, look for time warps: 831 * 832 * - we have stored at least one lastsweek and 833 * - the sweek didn't increase by one and 834 * - we didn't wrap to a new GPS week 835 * 836 * Then we warped. 837 */ 838 if (up->lastsweek == sweek) 839 jupiter_debug(peer, 840 "jupiter_parse_t: gps sweek not incrementing (%d)\n", 841 sweek); 842 else if (up->lastsweek != 2 * WEEKSECS && 843 up->lastsweek + 1 != sweek && 844 !(sweek == 0 && up->lastsweek == WEEKSECS - 1)) 845 jupiter_debug(peer, 846 "jupiter_parse_t: gps sweek jumped (was %d, now %d)\n", 847 up->lastsweek, sweek); 848 up->lastsweek = sweek; 849 850 /* This timecode describes next pulse */ 851 last_timecode = up->timecode; 852 up->timecode = (u_int32)JAN_1970 + 853 GPS_EPOCH + (up->gweek * WEEKSECS) + sweek; 854 855 if (last_timecode == 0) 856 /* XXX debugging */ 857 jupiter_debug(peer, 858 "jupiter_parse_t: UTC <none> (gweek/sweek %u/%u)\n", 859 up->gweek, sweek); 860 else { 861 /* XXX debugging */ 862 t = last_timecode - (u_int32)JAN_1970; 863 tm = gmtime(&t); 864 cp = asctime(tm); 865 866 jupiter_debug(peer, 867 "jupiter_parse_t: UTC %.24s (gweek/sweek %u/%u)\n", 868 cp, up->gweek, sweek); 869 870 /* Billboard last_timecode (which is now the current time) */ 871 jt = &cal; 872 caljulian(last_timecode, jt); 873 pp = peer->procptr; 874 pp->year = jt->year; 875 pp->day = jt->yearday; 876 pp->hour = jt->hour; 877 pp->minute = jt->minute; 878 pp->second = jt->second; 879 pp->msec = 0; 880 pp->usec = 0; 881 } 882 883 /* XXX debugging */ 884 tm = gmtime(&up->ppsev.tv.tv_sec); 885 cp = asctime(tm); 886 flags = getshort(jp->flags); 887 jupiter_debug(peer, 888 "jupiter_parse_t: PPS %.19s.%06lu %.4s (serial %u)%s\n", 889 cp, up->ppsev.tv.tv_usec, cp + 20, up->ppsev.serial, 890 (flags & JUPITER_O_PULSE_VALID) == 0 ? 891 " NOT VALID" : ""); 892 893 /* Toss if not designated "valid" by the gps */ 894 if ((flags & JUPITER_O_PULSE_VALID) == 0) { 895 refclock_report(peer, CEVNT_BADTIME); 896 return ("time mark not valid"); 897 } 898 899 /* We better be sync'ed to UTC... */ 900 if ((flags & JUPITER_O_PULSE_UTC) == 0) { 901 refclock_report(peer, CEVNT_BADTIME); 902 return ("time mark not sync'ed to UTC"); 903 } 904 905 return (NULL); 906} 907 908/* 909 * Process a PPS signal, returning a timestamp. 910 */ 911static int 912jupiter_pps(register struct peer *peer) 913{ 914 register struct refclockproc *pp; 915 register struct jupiterunit *up; 916 register int firsttime; 917 struct timeval ntp_tv; 918 919 pp = peer->procptr; 920 up = (struct jupiterunit *)pp->unitptr; 921 922 /* 923 * Grab the timestamp of the PPS signal. 924 */ 925 firsttime = (up->ppsev.tv.tv_sec == 0); 926 if (ioctl(pp->io.fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { 927 /* XXX Actually, if this fails, we're pretty much screwed */ 928 jupiter_debug(peer, "jupiter_pps: CIOGETEV: %s\n", 929 strerror(errno)); 930 refclock_report(peer, CEVNT_FAULT); 931 return (1); 932 } 933 934 /* 935 * Check pps serial number against last one 936 */ 937 if (!firsttime && up->lastserial + 1 != up->ppsev.serial) { 938 if (up->ppsev.serial == up->lastserial) 939 jupiter_debug(peer, "jupiter_pps: no new pps event\n"); 940 else 941 jupiter_debug(peer, 942 "jupiter_pps: missed %d pps events\n", 943 up->ppsev.serial - up->lastserial - 1); 944 up->lastserial = up->ppsev.serial; 945 refclock_report(peer, CEVNT_FAULT); 946 return (1); 947 } 948 up->lastserial = up->ppsev.serial; 949 950 /* 951 * Return the timestamp in pp->lastrec 952 */ 953 ntp_tv = up->ppsev.tv; 954 ntp_tv.tv_sec += (u_int32)JAN_1970; 955 TVTOTS(&ntp_tv, &pp->lastrec); 956 957 return (0); 958} 959 960/* 961 * jupiter_debug - print debug messages 962 */ 963#if __STDC__ 964static void 965jupiter_debug(struct peer *peer, char *fmt, ...) 966#else 967static void 968jupiter_debug(peer, fmt, va_alist) 969 struct peer *peer; 970 char *fmt; 971#endif 972{ 973 va_list ap; 974 975 if (debug) { 976 977#if __STDC__ 978 va_start(ap, fmt); 979#else 980 va_start(ap); 981#endif 982 /* 983 * Print debug message to stdout 984 * In the future, we may want to get get more creative... 985 */ 986 vfprintf(stderr, fmt, ap); 987 988 va_end(ap); 989 } 990} 991 992/* Checksum and transmit a message to the Jupiter */ 993static char * 994jupiter_send(register struct peer *peer, register struct jheader *hp) 995{ 996 register u_int len, size; 997 register int cc; 998 register u_short *sp; 999 static char errstr[132]; 1000 1001 size = sizeof(*hp); 1002 hp->hsum = putshort(jupiter_cksum((u_short *)hp, 1003 (size / sizeof(u_short)) - 1)); 1004 len = getshort(hp->len); 1005 if (len > 0) { 1006 sp = (u_short *)(hp + 1); 1007 sp[len] = putshort(jupiter_cksum(sp, len)); 1008 size += (len + 1) * sizeof(u_short); 1009 } 1010 1011 if ((cc = write(peer->procptr->io.fd, (char *)hp, size)) < 0) { 1012 (void)sprintf(errstr, "write: %s", strerror(errno)); 1013 return (errstr); 1014 } else if (cc != size) { 1015 (void)sprintf(errstr, "short write (%d != %d)", cc, size); 1016 return (errstr); 1017 } 1018 return (NULL); 1019} 1020 1021/* Request periodic message output */ 1022static struct { 1023 struct jheader jheader; 1024 struct jrequest jrequest; 1025} reqmsg = { 1026 { putshort(JUPITER_SYNC), 0, 1027 putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 1028 0, putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 1029 JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 }, 1030 { 0, 0, 0, 0 } 1031}; 1032 1033/* An interval of zero means to output on trigger */ 1034static void 1035jupiter_reqmsg(register struct peer *peer, register u_int id, 1036 register u_int interval) 1037{ 1038 register struct jheader *hp; 1039 register struct jrequest *rp; 1040 register char *cp; 1041 1042 hp = &reqmsg.jheader; 1043 hp->id = putshort(id); 1044 rp = &reqmsg.jrequest; 1045 rp->trigger = putshort(interval == 0); 1046 rp->interval = putshort(interval); 1047 if ((cp = jupiter_send(peer, hp)) != NULL) 1048 jupiter_debug(peer, "jupiter_reqmsg: %u: %s\n", id, cp); 1049} 1050 1051/* Cancel periodic message output */ 1052static struct jheader canmsg = { 1053 putshort(JUPITER_SYNC), 0, 0, 0, 1054 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), 1055 0 1056}; 1057 1058static void 1059jupiter_canmsg(register struct peer *peer, register u_int id) 1060{ 1061 register struct jheader *hp; 1062 register char *cp; 1063 1064 hp = &canmsg; 1065 hp->id = putshort(id); 1066 if ((cp = jupiter_send(peer, hp)) != NULL) 1067 jupiter_debug(peer, "jupiter_canmsg: %u: %s\n", id, cp); 1068} 1069 1070/* Request a single message output */ 1071static struct jheader reqonemsg = { 1072 putshort(JUPITER_SYNC), 0, 0, 0, 1073 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), 1074 0 1075}; 1076 1077static void 1078jupiter_reqonemsg(register struct peer *peer, register u_int id) 1079{ 1080 register struct jheader *hp; 1081 register char *cp; 1082 1083 hp = &reqonemsg; 1084 hp->id = putshort(id); 1085 if ((cp = jupiter_send(peer, hp)) != NULL) 1086 jupiter_debug(peer, "jupiter_reqonemsg: %u: %s\n", id, cp); 1087} 1088 1089/* Set the platform dynamics */ 1090static struct { 1091 struct jheader jheader; 1092 struct jplat jplat; 1093} platmsg = { 1094 { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 1095 putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 1096 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, 1097 { 0, 0, 0 } 1098}; 1099 1100static void 1101jupiter_platform(register struct peer *peer, register u_int platform) 1102{ 1103 register struct jheader *hp; 1104 register struct jplat *pp; 1105 register char *cp; 1106 1107 hp = &platmsg.jheader; 1108 pp = &platmsg.jplat; 1109 pp->platform = putshort(platform); 1110 if ((cp = jupiter_send(peer, hp)) != NULL) 1111 jupiter_debug(peer, "jupiter_platform: %u: %s\n", platform, cp); 1112} 1113 1114/* Checksum "len" shorts */ 1115static u_short 1116jupiter_cksum(register u_short *sp, register u_int len) 1117{ 1118 register u_short sum, x; 1119 1120 sum = 0; 1121 while (len-- > 0) { 1122 x = *sp++; 1123 sum += getshort(x); 1124 } 1125 return (~sum + 1); 1126} 1127 1128/* Return the size of the next message (or zero if we don't have it all yet) */ 1129static int 1130jupiter_recv(register struct peer *peer) 1131{ 1132 register int n, len, size, cc; 1133 register struct refclockproc *pp; 1134 register struct jupiterunit *up; 1135 register struct jheader *hp; 1136 register u_char *bp; 1137 register u_short *sp; 1138 1139 pp = peer->procptr; 1140 up = (struct jupiterunit *)pp->unitptr; 1141 1142 /* Must have at least a header's worth */ 1143 cc = sizeof(*hp); 1144 size = up->ssize; 1145 if (size < cc) 1146 return (0); 1147 1148 /* Search for the sync short if missing */ 1149 sp = up->sbuf; 1150 hp = (struct jheader *)sp; 1151 if (getshort(hp->sync) != JUPITER_SYNC) { 1152 /* Wasn't at the front, sync up */ 1153 jupiter_debug(peer, "syncing"); 1154 bp = (u_char *)sp; 1155 n = size; 1156 while (n >= 2) { 1157 if (bp[0] != (JUPITER_SYNC & 0xff)) { 1158 jupiter_debug(peer, "{0x%x}", bp[0]); 1159 ++bp; 1160 --n; 1161 continue; 1162 } 1163 if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 1164 break; 1165 jupiter_debug(peer, "{0x%x 0x%x}", bp[0], bp[1]); 1166 bp += 2; 1167 n -= 2; 1168 } 1169 jupiter_debug(peer, "\n"); 1170 /* Shuffle data to front of input buffer */ 1171 if (n > 0) 1172 memcpy(sp, bp, n); 1173 size = n; 1174 up->ssize = size; 1175 if (size < cc || hp->sync != JUPITER_SYNC) 1176 return (0); 1177 } 1178 1179 if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1180 getshort(hp->hsum)) { 1181 jupiter_debug(peer, "jupiter_recv: bad header checksum!\n"); 1182 /* This is drastic but checksum errors should be rare */ 1183 up->ssize = 0; 1184 return (0); 1185 } 1186 1187 /* Check for a payload */ 1188 len = getshort(hp->len); 1189 if (len > 0) { 1190 n = (len + 1) * sizeof(u_short); 1191 /* Not enough data yet */ 1192 if (size < cc + n) 1193 return (0); 1194 1195 /* Check payload checksum */ 1196 sp = (u_short *)(hp + 1); 1197 if (jupiter_cksum(sp, len) != getshort(sp[len])) { 1198 jupiter_debug(peer, 1199 "jupiter_recv: bad payload checksum!\n"); 1200 /* This is drastic but checksum errors should be rare */ 1201 up->ssize = 0; 1202 return (0); 1203 } 1204 cc += n; 1205 } 1206 return (cc); 1207} 1208 1209static int 1210jupiter_ttyinit(register struct peer *peer, register int fd) 1211{ 1212 struct termios termios; 1213 1214 memset((char *)&termios, 0, sizeof(termios)); 1215 if (cfsetispeed(&termios, B9600) < 0 || 1216 cfsetospeed(&termios, B9600) < 0) { 1217 jupiter_debug(peer, 1218 "jupiter_ttyinit: cfsetispeed/cfgetospeed: %s\n", 1219 strerror(errno)); 1220 return (0); 1221 } 1222#ifdef HAVE_CFMAKERAW 1223 cfmakeraw(&termios); 1224#else 1225 termios.c_iflag &= ~(IMAXBEL | IXOFF | INPCK | BRKINT | PARMRK | 1226 ISTRIP | INLCR | IGNCR | ICRNL | IXON | IGNPAR); 1227 termios.c_iflag |= IGNBRK; 1228 termios.c_oflag &= ~OPOST; 1229 termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | 1230 IEXTEN | NOFLSH | TOSTOP | PENDIN); 1231 termios.c_cflag &= ~(CSIZE | PARENB); 1232 termios.c_cflag |= CS8 | CREAD; 1233 termios.c_cc[VMIN] = 1; 1234#endif 1235 termios.c_cflag |= CLOCAL; 1236 if (tcsetattr(fd, TCSANOW, &termios) < 0) { 1237 jupiter_debug(peer, "jupiter_ttyinit: tcsetattr: %s\n", 1238 strerror(errno)); 1239 return (0); 1240 } 1241 1242#ifdef TIOCSPPS 1243 if (ioctl(fd, TIOCSPPS, (char *)&fdpps) < 0) { 1244 jupiter_debug(peer, "jupiter_ttyinit: TIOCSPPS: %s\n", 1245 strerror(errno)); 1246 return (0); 1247 } 1248#endif 1249#ifdef I_PUSH 1250 if (ioctl(fd, I_PUSH, "ppsclock") < 0) { 1251 jupiter_debug(peer, "jupiter_ttyinit: push ppsclock: %s\n", 1252 strerror(errno)); 1253 return (0); 1254 } 1255#endif 1256 1257 return (1); 1258} 1259 1260#else /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ 1261int refclock_jupiter_bs; 1262#endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ 1263