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 "ntpd.h" 41 #include "ntp_io.h" 42 #include "ntp_refclock.h" 43 #include "ntp_unixtime.h" 44 #include "ntp_stdlib.h" 45 #include "ntp_calendar.h" 46 47 #include <stdio.h> 48 #include <ctype.h> 49 50 #include "jupiter.h" 51 52 #include <sys/ppsclock.h> 53 54 #ifdef XNTP_BIG_ENDIAN 55 #define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 56 #define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) 57 #else 58 #define getshort(s) (s) 59 #define putshort(s) (s) 60 #endif 61 62 /* XXX */ 63 #ifdef sun 64 char *strerror(int); 65 #endif 66 67 /* 68 * This driver supports the Rockwell Jupiter GPS Receiver board 69 * adapted to precision timing applications. It requires the 70 * ppsclock line discipline or streams module described in the 71 * Line Disciplines and Streams Drivers page. It also requires a 72 * gadget box and 1-PPS level converter, such as described in the 73 * Pulse-per-second (PPS) Signal Interfacing page. 74 * 75 * It may work (with minor modifications) with other Rockwell GPS 76 * receivers such as the CityTracker. 77 */ 78 79 /* 80 * GPS Definitions 81 */ 82 #define DEVICE "/dev/gps%d" /* device name and unit */ 83 #define SPEED232 B9600 /* baud */ 84 85 /* 86 * The number of raw samples which we acquire to derive a single estimate. 87 * NSAMPLES ideally should not exceed the default poll interval 64. 88 * NKEEP must be a power of 2 to simplify the averaging process. 89 */ 90 #define NSAMPLES 64 91 #define NKEEP 8 92 #define REFCLOCKMAXDISPERSE .25 /* max sample dispersion */ 93 94 /* 95 * Radio interface parameters 96 */ 97 #define PRECISION (-18) /* precision assumed (about 4 us) */ 98 #define REFID "GPS\0" /* reference id */ 99 #define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ 100 #define DEFFUDGETIME 0 /* default fudge time (ms) */ 101 102 /* Unix timestamp for the GPS epoch: January 6, 1980 */ 103 #define GPS_EPOCH 315964800 104 105 /* Double short to unsigned int */ 106 #define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 107 108 /* Double short to signed int */ 109 #define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) 110 111 /* One week's worth of seconds */ 112 #define WEEKSECS (7 * 24 * 60 * 60) 113 114 /* 115 * Jupiter unit control structure. 116 */ 117 struct jupiterunit { 118 u_int pollcnt; /* poll message counter */ 119 u_int polled; /* Hand in a time sample? */ 120 u_int lastserial; /* last pps serial number */ 121 struct ppsclockev ppsev; /* PPS control structure */ 122 u_int gweek; /* current GPS week number */ 123 u_int32 lastsweek; /* last seconds into GPS week */ 124 u_int32 timecode; /* current ntp timecode */ 125 u_int32 stime; /* used to detect firmware bug */ 126 int wantid; /* don't reconfig on channel id msg */ 127 u_int moving; /* mobile platform? */ 128 u_long sloppyclockflag; /* fudge flags */ 129 u_int known; /* position known yet? */ 130 int coderecv; /* total received samples */ 131 int nkeep; /* number of samples to preserve */ 132 int rshift; /* number of rshifts for division */ 133 l_fp filter[NSAMPLES]; /* offset filter */ 134 l_fp lastref; /* last reference timestamp */ 135 u_short sbuf[512]; /* local input buffer */ 136 int ssize; /* space used in sbuf */ 137 }; 138 139 /* 140 * Function prototypes 141 */ 142 static void jupiter_canmsg P((struct peer *, u_int)); 143 static u_short jupiter_cksum P((u_short *, u_int)); 144 #ifdef QSORT_USES_VOID_P 145 int jupiter_cmpl_fp P((const void *, const void *)); 146 #else 147 int jupiter_cmpl_fp P((const l_fp *, const l_fp *)); 148 #endif /* not QSORT_USES_VOID_P */ 149 static void jupiter_config P((struct peer *)); 150 static void jupiter_debug P((struct peer *, char *, ...)) 151 __attribute__ ((format (printf, 2, 3))); 152 static char * jupiter_offset P((struct peer *)); 153 static char * jupiter_parse_t P((struct peer *, u_short *)); 154 static void jupiter_platform P((struct peer *, u_int)); 155 static void jupiter_poll P((int, struct peer *)); 156 static int jupiter_pps P((struct peer *)); 157 static char * jupiter_process P((struct peer *)); 158 static int jupiter_recv P((struct peer *)); 159 static void jupiter_receive P((register struct recvbuf *rbufp)); 160 static void jupiter_reqmsg P((struct peer *, u_int, u_int)); 161 static void jupiter_reqonemsg P((struct peer *, u_int)); 162 static char * jupiter_send P((struct peer *, struct jheader *)); 163 static void jupiter_shutdown P((int, struct peer *)); 164 static int jupiter_start P((int, struct peer *)); 165 static int jupiter_ttyinit P((struct peer *, int)); 166 167 /* 168 * Transfer vector 169 */ 170 struct refclock refclock_jupiter = { 171 jupiter_start, /* start up driver */ 172 jupiter_shutdown, /* shut down driver */ 173 jupiter_poll, /* transmit poll message */ 174 noentry, /* (clock control) */ 175 noentry, /* (clock init) */ 176 noentry, /* (clock buginfo) */ 177 NOFLAGS /* not used */ 178 }; 179 180 /* 181 * jupiter_start - open the devices and initialize data for processing 182 */ 183 static int 184 jupiter_start( 185 register int unit, 186 register struct peer *peer 187 ) 188 { 189 struct refclockproc *pp; 190 register struct jupiterunit *up; 191 register int fd; 192 char gpsdev[20]; 193 194 /* 195 * Open serial port 196 */ 197 (void)sprintf(gpsdev, DEVICE, unit); 198 fd = open(gpsdev, O_RDWR 199 #ifdef O_NONBLOCK 200 | O_NONBLOCK 201 #endif 202 , 0); 203 if (fd < 0) { 204 jupiter_debug(peer, "jupiter_start: open %s: %s\n", 205 gpsdev, strerror(errno)); 206 return (0); 207 } 208 if (!jupiter_ttyinit(peer, fd)) 209 return (0); 210 211 /* Allocate unit structure */ 212 if ((up = (struct jupiterunit *) 213 emalloc(sizeof(struct jupiterunit))) == NULL) { 214 (void) close(fd); 215 return (0); 216 } 217 memset((char *)up, 0, sizeof(struct jupiterunit)); 218 pp = peer->procptr; 219 pp->io.clock_recv = jupiter_receive; 220 pp->io.srcclock = (caddr_t)peer; 221 pp->io.datalen = 0; 222 pp->io.fd = fd; 223 if (!io_addclock(&pp->io)) { 224 (void) close(fd); 225 free(up); 226 return (0); 227 } 228 pp->unitptr = (caddr_t)up; 229 230 /* 231 * Initialize miscellaneous variables 232 */ 233 peer->precision = PRECISION; 234 pp->clockdesc = DESCRIPTION; 235 memcpy((char *)&pp->refid, REFID, 4); 236 237 238 /* Ensure the receiver is properly configured */ 239 jupiter_config(peer); 240 241 /* Turn on pulse gathering by requesting the first sample */ 242 if (ioctl(fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { 243 jupiter_debug(peer, "jupiter_ttyinit: CIOGETEV: %s\n", 244 strerror(errno)); 245 (void) close(fd); 246 free(up); 247 return (0); 248 } 249 up->lastserial = up->ppsev.serial; 250 memset(&up->ppsev, 0, sizeof(up->ppsev)); 251 return (1); 252 } 253 254 /* 255 * jupiter_shutdown - shut down the clock 256 */ 257 static void 258 jupiter_shutdown(register int unit, register struct peer *peer) 259 { 260 register struct jupiterunit *up; 261 struct refclockproc *pp; 262 263 pp = peer->procptr; 264 up = (struct jupiterunit *)pp->unitptr; 265 io_closeclock(&pp->io); 266 free(up); 267 } 268 269 /* 270 * jupiter_config - Configure the receiver 271 */ 272 static void 273 jupiter_config(register struct peer *peer) 274 { 275 register int i; 276 register struct jupiterunit *up; 277 register struct refclockproc *pp; 278 279 pp = peer->procptr; 280 up = (struct jupiterunit *)pp->unitptr; 281 282 /* 283 * Initialize the unit variables 284 * 285 * STRANGE BEHAVIOUR WARNING: The fudge flags are not available 286 * at the time jupiter_start is called. These are set later, 287 * and so the code must be prepared to handle changing flags. 288 */ 289 up->sloppyclockflag = pp->sloppyclockflag; 290 if (pp->sloppyclockflag & CLK_FLAG2) { 291 up->moving = 1; /* Receiver on mobile platform */ 292 msyslog(LOG_DEBUG, "jupiter_config: mobile platform"); 293 } else { 294 up->moving = 0; /* Static Installation */ 295 } 296 297 /* XXX fludge flags don't make the trip from the config to here... */ 298 #ifdef notdef 299 /* Configure for trailing edge triggers */ 300 #ifdef CIOSETTET 301 i = ((pp->sloppyclockflag & CLK_FLAG3) != 0); 302 jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n", 303 pp->sloppyclockflag); 304 if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0) 305 msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i); 306 #else 307 if (pp->sloppyclockflag & CLK_FLAG3) 308 msyslog(LOG_DEBUG, "jupiter_configure: \ 309 No kernel support for trailing edge trigger"); 310 #endif 311 #endif 312 313 up->pollcnt = 2; 314 up->polled = 0; 315 up->known = 0; 316 up->gweek = 0; 317 up->lastsweek = 2 * WEEKSECS; 318 up->timecode = 0; 319 up->stime = 0; 320 up->ssize = 0; 321 up->coderecv = 0; 322 up->nkeep = NKEEP; 323 if (up->nkeep > NSAMPLES) 324 up->nkeep = NSAMPLES; 325 if (up->nkeep >= 1) 326 up->rshift = 0; 327 if (up->nkeep >= 2) 328 up->rshift = 1; 329 if (up->nkeep >= 4) 330 up->rshift = 2; 331 if (up->nkeep >= 8) 332 up->rshift = 3; 333 if (up->nkeep >= 16) 334 up->rshift = 4; 335 if (up->nkeep >= 32) 336 up->rshift = 5; 337 if (up->nkeep >= 64) 338 up->rshift = 6; 339 up->nkeep = 1; 340 i = up->rshift; 341 while (i > 0) { 342 up->nkeep *= 2; 343 i--; 344 } 345 346 /* Stop outputting all messages */ 347 jupiter_canmsg(peer, JUPITER_ALL); 348 349 /* Request the receiver id so we can syslog the firmware version */ 350 jupiter_reqonemsg(peer, JUPITER_O_ID); 351 352 /* Flag that this the id was requested (so we don't get called again) */ 353 up->wantid = 1; 354 355 /* Request perodic time mark pulse messages */ 356 jupiter_reqmsg(peer, JUPITER_O_PULSE, 1); 357 358 /* Set application platform type */ 359 if (up->moving) 360 jupiter_platform(peer, JUPITER_I_PLAT_MED); 361 else 362 jupiter_platform(peer, JUPITER_I_PLAT_LOW); 363 } 364 365 /* 366 * jupiter_poll - jupiter watchdog routine 367 */ 368 static void 369 jupiter_poll(register int unit, register struct peer *peer) 370 { 371 register struct jupiterunit *up; 372 register struct refclockproc *pp; 373 374 pp = peer->procptr; 375 up = (struct jupiterunit *)pp->unitptr; 376 377 /* 378 * You don't need to poll this clock. It puts out timecodes 379 * once per second. If asked for a timestamp, take note. 380 * The next time a timecode comes in, it will be fed back. 381 */ 382 383 /* 384 * If we haven't had a response in a while, reset the receiver. 385 */ 386 if (up->pollcnt > 0) { 387 up->pollcnt--; 388 } else { 389 refclock_report(peer, CEVNT_TIMEOUT); 390 391 /* Request the receiver id to trigger a reconfig */ 392 jupiter_reqonemsg(peer, JUPITER_O_ID); 393 up->wantid = 0; 394 } 395 396 /* 397 * polled every 64 seconds. Ask jupiter_receive to hand in 398 * a timestamp. 399 */ 400 up->polled = 1; 401 pp->polls++; 402 } 403 404 /* 405 * jupiter_receive - receive gps data 406 * Gag me! 407 */ 408 static void 409 jupiter_receive(register struct recvbuf *rbufp) 410 { 411 register int bpcnt, cc, size, ppsret; 412 register u_int32 last_timecode, laststime; 413 register char *cp; 414 register u_char *bp; 415 register u_short *sp; 416 register u_long sloppyclockflag; 417 register struct jupiterunit *up; 418 register struct jid *ip; 419 register struct jheader *hp; 420 register struct refclockproc *pp; 421 register struct peer *peer; 422 423 /* Initialize pointers and read the timecode and timestamp */ 424 peer = (struct peer *)rbufp->recv_srcclock; 425 pp = peer->procptr; 426 up = (struct jupiterunit *)pp->unitptr; 427 428 /* 429 * If operating mode has been changed, then reinitialize the receiver 430 * before doing anything else. 431 */ 432 /* XXX Sloppy clock flags are broken!! */ 433 sloppyclockflag = up->sloppyclockflag; 434 up->sloppyclockflag = pp->sloppyclockflag; 435 if ((pp->sloppyclockflag & CLK_FLAG2) != 436 (sloppyclockflag & CLK_FLAG2)) { 437 jupiter_debug(peer, 438 "jupiter_receive: mode switch: reset receiver\n"); 439 jupiter_config(peer); 440 return; 441 } 442 443 up->pollcnt = 2; 444 445 bp = (u_char *)rbufp->recv_buffer; 446 bpcnt = rbufp->recv_length; 447 448 /* This shouldn't happen */ 449 if (bpcnt > sizeof(up->sbuf) - up->ssize) 450 bpcnt = sizeof(up->sbuf) - up->ssize; 451 452 /* Append to input buffer */ 453 memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); 454 up->ssize += bpcnt; 455 456 /* While there's at least a header and we parse a intact message */ 457 while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) { 458 hp = (struct jheader *)up->sbuf; 459 sp = (u_short *)(hp + 1); 460 size = cc - sizeof(*hp); 461 switch (getshort(hp->id)) { 462 463 case JUPITER_O_PULSE: 464 if (size != sizeof(struct jpulse)) { 465 jupiter_debug(peer, 466 "jupiter_receive: pulse: len %d != %u\n", 467 size, (int)sizeof(struct jpulse)); 468 refclock_report(peer, CEVNT_BADREPLY); 469 break; 470 } 471 472 /* 473 * There appears to be a firmware bug related 474 * to the pulse message; in addition to the one 475 * per second messages, we get an extra pulse 476 * message once an hour (on the anniversary of 477 * the cold start). It seems to come 200 ms 478 * after the one requested. So if we've seen a 479 * pulse message in the last 210 ms, we skip 480 * this one. 481 */ 482 laststime = up->stime; 483 up->stime = DS2UI(((struct jpulse *)sp)->stime); 484 if (laststime != 0 && up->stime - laststime <= 21) { 485 jupiter_debug(peer, "jupiter_receive: \ 486 avoided firmware bug (stime %.2f, laststime %.2f)\n", 487 (double)up->stime * 0.01, (double)laststime * 0.01); 488 break; 489 } 490 491 /* Retrieve pps timestamp */ 492 ppsret = jupiter_pps(peer); 493 494 /* Parse timecode (even when there's no pps) */ 495 last_timecode = up->timecode; 496 if ((cp = jupiter_parse_t(peer, sp)) != NULL) { 497 jupiter_debug(peer, 498 "jupiter_receive: pulse: %s\n", cp); 499 break; 500 } 501 502 /* Bail if we didn't get a pps timestamp */ 503 if (ppsret) 504 break; 505 506 /* Bail if we don't have the last timecode yet */ 507 if (last_timecode == 0) 508 break; 509 510 /* Add the new sample to a median filter */ 511 if ((cp = jupiter_offset(peer)) != NULL) { 512 jupiter_debug(peer, 513 "jupiter_receive: offset: %s\n", cp); 514 refclock_report(peer, CEVNT_BADTIME); 515 break; 516 } 517 518 /* 519 * The clock will blurt a timecode every second 520 * but we only want one when polled. If we 521 * havn't been polled, bail out. 522 */ 523 if (!up->polled) 524 break; 525 526 /* 527 * It's a live one! Remember this time. 528 */ 529 pp->lasttime = current_time; 530 531 /* 532 * Determine the reference clock offset and 533 * dispersion. NKEEP of NSAMPLE offsets are 534 * passed through a median filter. 535 * Save the (filtered) offset and dispersion in 536 * pp->offset and pp->disp. 537 */ 538 if ((cp = jupiter_process(peer)) != NULL) { 539 jupiter_debug(peer, 540 "jupiter_receive: process: %s\n", cp); 541 refclock_report(peer, CEVNT_BADTIME); 542 break; 543 } 544 /* 545 * Return offset and dispersion to control 546 * module. We use lastrec as both the reference 547 * time and receive time in order to avoid 548 * being cute, like setting the reference time 549 * later than the receive time, which may cause 550 * a paranoid protocol module to chuck out the 551 * data. 552 */ 553 jupiter_debug(peer, 554 "jupiter_receive: process time: \ 555 %4d-%03d %02d:%02d:%02d at %s, %s\n", 556 pp->year, pp->day, 557 pp->hour, pp->minute, pp->second, 558 prettydate(&pp->lastrec), lfptoa(&pp->offset, 6)); 559 560 refclock_receive(peer); 561 562 /* 563 * We have succeeded in answering the poll. 564 * Turn off the flag and return 565 */ 566 up->polled = 0; 567 break; 568 569 case JUPITER_O_ID: 570 if (size != sizeof(struct jid)) { 571 jupiter_debug(peer, 572 "jupiter_receive: id: len %d != %u\n", 573 size, (int)sizeof(struct jid)); 574 refclock_report(peer, CEVNT_BADREPLY); 575 break; 576 } 577 /* 578 * If we got this message because the Jupiter 579 * just powered up, it needs to be reconfigured. 580 */ 581 ip = (struct jid *)sp; 582 jupiter_debug(peer, 583 "jupiter_receive: >> %s chan ver %s, %s (%s)\n", 584 ip->chans, ip->vers, ip->date, ip->opts); 585 msyslog(LOG_DEBUG, 586 "jupiter_receive: %s chan ver %s, %s (%s)\n", 587 ip->chans, ip->vers, ip->date, ip->opts); 588 if (up->wantid) 589 up->wantid = 0; 590 else { 591 jupiter_debug(peer, 592 "jupiter_receive: reset receiver\n"); 593 jupiter_config(peer); 594 /* Rese since jupiter_config() just zeroed it */ 595 up->ssize = cc; 596 } 597 break; 598 599 default: 600 jupiter_debug(peer, 601 "jupiter_receive: >> unknown message id %d\n", 602 getshort(hp->id)); 603 break; 604 } 605 up->ssize -= cc; 606 if (up->ssize < 0) { 607 fprintf(stderr, "jupiter_recv: negative ssize!\n"); 608 abort(); 609 } else if (up->ssize > 0) 610 memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); 611 } 612 record_clock_stats(&peer->srcadr, "<timecode is binary>"); 613 } 614 615 /* 616 * jupiter_offset - Calculate the offset, and add to the rolling filter. 617 */ 618 static char * 619 jupiter_offset(register struct peer *peer) 620 { 621 register struct jupiterunit *up; 622 register struct refclockproc *pp; 623 register int i; 624 l_fp offset; 625 626 pp = peer->procptr; 627 up = (struct jupiterunit *)pp->unitptr; 628 629 /* 630 * Calculate the offset 631 */ 632 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 633 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) { 634 return ("jupiter_process: clocktime failed"); 635 } 636 if (pp->usec) { 637 TVUTOTSF(pp->usec, offset.l_uf); 638 } else { 639 MSUTOTSF(pp->msec, offset.l_uf); 640 } 641 L_ADD(&offset, &pp->fudgetime1); 642 up->lastref = offset; /* save last reference time */ 643 L_SUB(&offset, &pp->lastrec); /* form true offset */ 644 645 /* 646 * A rolling filter. Initialize first time around. 647 */ 648 i = ((up->coderecv)) % NSAMPLES; 649 650 up->filter[i] = offset; 651 if (up->coderecv == 0) 652 for (i = 1; (u_int) i < NSAMPLES; i++) 653 up->filter[i] = up->filter[0]; 654 up->coderecv++; 655 656 return (NULL); 657 } 658 659 /* 660 * jupiter_process - process the sample from the clock, 661 * passing it through a median filter and optionally averaging 662 * the samples. Returns offset and dispersion in "up" structure. 663 */ 664 static char * 665 jupiter_process(register struct peer *peer) 666 { 667 register struct jupiterunit *up; 668 register struct refclockproc *pp; 669 register int i, n; 670 register int j, k; 671 l_fp offset, median, lftmp; 672 u_fp disp; 673 l_fp off[NSAMPLES]; 674 675 pp = peer->procptr; 676 up = (struct jupiterunit *)pp->unitptr; 677 678 /* 679 * Copy the raw offsets and sort into ascending order 680 */ 681 for (i = 0; i < NSAMPLES; i++) 682 off[i] = up->filter[i]; 683 qsort((char *)off, (size_t)NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); 684 685 /* 686 * Reject the furthest from the median of NSAMPLES samples until 687 * NKEEP samples remain. 688 */ 689 i = 0; 690 n = NSAMPLES; 691 while ((n - i) > up->nkeep) { 692 lftmp = off[n - 1]; 693 median = off[(n + i) / 2]; 694 L_SUB(&lftmp, &median); 695 L_SUB(&median, &off[i]); 696 if (L_ISHIS(&median, &lftmp)) { 697 /* reject low end */ 698 i++; 699 } else { 700 /* reject high end */ 701 n--; 702 } 703 } 704 705 /* 706 * Copy key values to the billboard to measure performance. 707 */ 708 pp->lastref = up->lastref; 709 pp->coderecv = up->coderecv; 710 pp->filter[0] = off[0]; /* smallest offset */ 711 pp->filter[1] = off[NSAMPLES-1]; /* largest offset */ 712 for (j = 2, k = i; k < n; j++, k++) 713 pp->filter[j] = off[k]; /* offsets actually examined */ 714 715 /* 716 * Compute the dispersion based on the difference between the 717 * extremes of the remaining offsets. Add to this the time since 718 * the last clock update, which represents the dispersion 719 * increase with time. We know that NTP_MAXSKEW is 16. If the 720 * sum is greater than the allowed sample dispersion, bail out. 721 * If the loop is unlocked, return the most recent offset; 722 * otherwise, return the median offset. 723 */ 724 lftmp = off[n - 1]; 725 L_SUB(&lftmp, &off[i]); 726 disp = LFPTOFP(&lftmp); 727 if (disp > REFCLOCKMAXDISPERSE) 728 return ("Maximum dispersion exceeded"); 729 730 /* 731 * Now compute the offset estimate. If fudge flag 1 732 * is set, average the remainder, otherwise pick the 733 * median. 734 */ 735 if (pp->sloppyclockflag & CLK_FLAG1) { 736 L_CLR(&lftmp); 737 while (i < n) { 738 L_ADD(&lftmp, &off[i]); 739 i++; 740 } 741 i = up->rshift; 742 while (i > 0) { 743 L_RSHIFT(&lftmp); 744 i--; 745 } 746 offset = lftmp; 747 } else { 748 i = (n + i) / 2; 749 offset = off[i]; 750 } 751 752 /* 753 * The payload: filtered offset and dispersion. 754 */ 755 756 pp->offset = offset; 757 pp->disp = disp; 758 759 return (NULL); 760 761 } 762 763 /* Compare two l_fp's, used with qsort() */ 764 #ifdef QSORT_USES_VOID_P 765 int 766 jupiter_cmpl_fp(register const void *p1, register const void *p2) 767 #else 768 int 769 jupiter_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 784 static char * 785 jupiter_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 */ 911 static int 912 jupiter_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 defined(__STDC__) 964 static void 965 jupiter_debug(struct peer *peer, char *fmt, ...) 966 #else 967 static void 968 jupiter_debug(peer, fmt, va_alist) 969 struct peer *peer; 970 char *fmt; 971 #endif /* __STDC__ */ 972 { 973 va_list ap; 974 975 if (debug) { 976 977 #if defined(__STDC__) 978 va_start(ap, fmt); 979 #else 980 va_start(ap); 981 #endif /* __STDC__ */ 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 */ 993 static char * 994 jupiter_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 */ 1022 static 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 */ 1034 static void 1035 jupiter_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 */ 1052 static 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 1058 static void 1059 jupiter_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 */ 1071 static 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 1077 static void 1078 jupiter_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 */ 1090 static 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 1100 static void 1101 jupiter_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 */ 1115 static u_short 1116 jupiter_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) */ 1129 static int 1130 jupiter_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 1209 static int 1210 jupiter_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) */ 1261 int refclock_jupiter_bs; 1262 #endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ 1263