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 65 char *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 */ 118 struct 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 */ 143 static void jupiter_canmsg P((struct peer *, u_int)); 144 static 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 */ 150 static void jupiter_config P((struct peer *)); 151 static void jupiter_debug P((struct peer *, char *, ...)) 152 __attribute__ ((format (printf, 2, 3))); 153 static char * jupiter_offset P((struct peer *)); 154 static char * jupiter_parse_t P((struct peer *, u_short *)); 155 static void jupiter_platform P((struct peer *, u_int)); 156 static void jupiter_poll P((int, struct peer *)); 157 static int jupiter_pps P((struct peer *)); 158 static char * jupiter_process P((struct peer *)); 159 static int jupiter_recv P((struct peer *)); 160 static void jupiter_receive P((register struct recvbuf *rbufp)); 161 static void jupiter_reqmsg P((struct peer *, u_int, u_int)); 162 static void jupiter_reqonemsg P((struct peer *, u_int)); 163 static char * jupiter_send P((struct peer *, struct jheader *)); 164 static void jupiter_shutdown P((int, struct peer *)); 165 static int jupiter_start P((int, struct peer *)); 166 static int jupiter_ttyinit P((struct peer *, int)); 167 168 /* 169 * Transfer vector 170 */ 171 struct 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 */ 184 static int 185 jupiter_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 */ 258 static void 259 jupiter_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 */ 273 static void 274 jupiter_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: \ 310 No 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 */ 369 static void 370 jupiter_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 */ 409 static void 410 jupiter_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: \ 487 avoided 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 */ 619 static char * 620 jupiter_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 */ 665 static char * 666 jupiter_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() */ 765 #ifdef QSORT_USES_VOID_P 766 int 767 jupiter_cmpl_fp(register const void *p1, register const void *p2) 768 #else 769 int 770 jupiter_cmpl_fp(register const l_fp *fp1, register const l_fp *fp2) 771 #endif 772 { 773 #ifdef QSORT_USES_VOID_P 774 register const l_fp *fp1 = (const l_fp *)p1; 775 register const l_fp *fp2 = (const l_fp *)p2; 776 #endif 777 778 if (!L_ISGEQ(fp1, fp2)) 779 return (-1); 780 if (L_ISEQU(fp1, fp2)) 781 return (0); 782 return (1); 783 } 784 785 static char * 786 jupiter_parse_t(register struct peer *peer, register u_short *sp) 787 { 788 register struct refclockproc *pp; 789 register struct jupiterunit *up; 790 register struct tm *tm; 791 register char *cp; 792 register struct jpulse *jp; 793 register struct calendar *jt; 794 register u_int32 sweek; 795 register u_int32 last_timecode; 796 register u_short flags; 797 time_t t; 798 struct calendar cal; 799 800 pp = peer->procptr; 801 up = (struct jupiterunit *)pp->unitptr; 802 jp = (struct jpulse *)sp; 803 804 /* The timecode is presented as seconds into the current GPS week */ 805 sweek = DS2UI(jp->sweek); 806 807 /* 808 * If we don't know the current GPS week, calculate it from the 809 * current time. (It's too bad they didn't include this 810 * important value in the pulse message). We'd like to pick it 811 * up from one of the other messages like gpos or chan but they 812 * don't appear to be synchronous with time keeping and changes 813 * too soon (something like 10 seconds before the new GPS 814 * week). 815 * 816 * If we already know the current GPS week, increment it when 817 * we wrap into a new week. 818 */ 819 if (up->gweek == 0) 820 up->gweek = (time(NULL) - GPS_EPOCH) / WEEKSECS; 821 else if (sweek == 0 && up->lastsweek == WEEKSECS - 1) { 822 ++up->gweek; 823 jupiter_debug(peer, 824 "jupiter_parse_t: NEW gps week %u\n", up->gweek); 825 } 826 827 /* 828 * See if the sweek stayed the same (this happens when there is 829 * no pps pulse). 830 * 831 * Otherwise, look for time warps: 832 * 833 * - we have stored at least one lastsweek and 834 * - the sweek didn't increase by one and 835 * - we didn't wrap to a new GPS week 836 * 837 * Then we warped. 838 */ 839 if (up->lastsweek == sweek) 840 jupiter_debug(peer, 841 "jupiter_parse_t: gps sweek not incrementing (%d)\n", 842 sweek); 843 else if (up->lastsweek != 2 * WEEKSECS && 844 up->lastsweek + 1 != sweek && 845 !(sweek == 0 && up->lastsweek == WEEKSECS - 1)) 846 jupiter_debug(peer, 847 "jupiter_parse_t: gps sweek jumped (was %d, now %d)\n", 848 up->lastsweek, sweek); 849 up->lastsweek = sweek; 850 851 /* This timecode describes next pulse */ 852 last_timecode = up->timecode; 853 up->timecode = (u_int32)JAN_1970 + 854 GPS_EPOCH + (up->gweek * WEEKSECS) + sweek; 855 856 if (last_timecode == 0) 857 /* XXX debugging */ 858 jupiter_debug(peer, 859 "jupiter_parse_t: UTC <none> (gweek/sweek %u/%u)\n", 860 up->gweek, sweek); 861 else { 862 /* XXX debugging */ 863 t = last_timecode - (u_int32)JAN_1970; 864 tm = gmtime(&t); 865 cp = asctime(tm); 866 867 jupiter_debug(peer, 868 "jupiter_parse_t: UTC %.24s (gweek/sweek %u/%u)\n", 869 cp, up->gweek, sweek); 870 871 /* Billboard last_timecode (which is now the current time) */ 872 jt = &cal; 873 caljulian(last_timecode, jt); 874 pp = peer->procptr; 875 pp->year = jt->year; 876 pp->day = jt->yearday; 877 pp->hour = jt->hour; 878 pp->minute = jt->minute; 879 pp->second = jt->second; 880 pp->msec = 0; 881 pp->usec = 0; 882 } 883 884 /* XXX debugging */ 885 tm = gmtime(&up->ppsev.tv.tv_sec); 886 cp = asctime(tm); 887 flags = getshort(jp->flags); 888 jupiter_debug(peer, 889 "jupiter_parse_t: PPS %.19s.%06lu %.4s (serial %u)%s\n", 890 cp, up->ppsev.tv.tv_usec, cp + 20, up->ppsev.serial, 891 (flags & JUPITER_O_PULSE_VALID) == 0 ? 892 " NOT VALID" : ""); 893 894 /* Toss if not designated "valid" by the gps */ 895 if ((flags & JUPITER_O_PULSE_VALID) == 0) { 896 refclock_report(peer, CEVNT_BADTIME); 897 return ("time mark not valid"); 898 } 899 900 /* We better be sync'ed to UTC... */ 901 if ((flags & JUPITER_O_PULSE_UTC) == 0) { 902 refclock_report(peer, CEVNT_BADTIME); 903 return ("time mark not sync'ed to UTC"); 904 } 905 906 return (NULL); 907 } 908 909 /* 910 * Process a PPS signal, returning a timestamp. 911 */ 912 static int 913 jupiter_pps(register struct peer *peer) 914 { 915 register struct refclockproc *pp; 916 register struct jupiterunit *up; 917 register int firsttime; 918 struct timeval ntp_tv; 919 920 pp = peer->procptr; 921 up = (struct jupiterunit *)pp->unitptr; 922 923 /* 924 * Grab the timestamp of the PPS signal. 925 */ 926 firsttime = (up->ppsev.tv.tv_sec == 0); 927 if (ioctl(pp->io.fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { 928 /* XXX Actually, if this fails, we're pretty much screwed */ 929 jupiter_debug(peer, "jupiter_pps: CIOGETEV: %s\n", 930 strerror(errno)); 931 refclock_report(peer, CEVNT_FAULT); 932 return (1); 933 } 934 935 /* 936 * Check pps serial number against last one 937 */ 938 if (!firsttime && up->lastserial + 1 != up->ppsev.serial) { 939 if (up->ppsev.serial == up->lastserial) 940 jupiter_debug(peer, "jupiter_pps: no new pps event\n"); 941 else 942 jupiter_debug(peer, 943 "jupiter_pps: missed %d pps events\n", 944 up->ppsev.serial - up->lastserial - 1); 945 up->lastserial = up->ppsev.serial; 946 refclock_report(peer, CEVNT_FAULT); 947 return (1); 948 } 949 up->lastserial = up->ppsev.serial; 950 951 /* 952 * Return the timestamp in pp->lastrec 953 */ 954 ntp_tv = up->ppsev.tv; 955 ntp_tv.tv_sec += (u_int32)JAN_1970; 956 TVTOTS(&ntp_tv, &pp->lastrec); 957 958 return (0); 959 } 960 961 /* 962 * jupiter_debug - print debug messages 963 */ 964 #if defined(__STDC__) 965 static void 966 jupiter_debug(struct peer *peer, char *fmt, ...) 967 #else 968 static void 969 jupiter_debug(peer, fmt, va_alist) 970 struct peer *peer; 971 char *fmt; 972 #endif /* __STDC__ */ 973 { 974 va_list ap; 975 976 if (debug) { 977 978 #if defined(__STDC__) 979 va_start(ap, fmt); 980 #else 981 va_start(ap); 982 #endif /* __STDC__ */ 983 /* 984 * Print debug message to stdout 985 * In the future, we may want to get get more creative... 986 */ 987 vfprintf(stderr, fmt, ap); 988 989 va_end(ap); 990 } 991 } 992 993 /* Checksum and transmit a message to the Jupiter */ 994 static char * 995 jupiter_send(register struct peer *peer, register struct jheader *hp) 996 { 997 register u_int len, size; 998 register int cc; 999 register u_short *sp; 1000 static char errstr[132]; 1001 1002 size = sizeof(*hp); 1003 hp->hsum = putshort(jupiter_cksum((u_short *)hp, 1004 (size / sizeof(u_short)) - 1)); 1005 len = getshort(hp->len); 1006 if (len > 0) { 1007 sp = (u_short *)(hp + 1); 1008 sp[len] = putshort(jupiter_cksum(sp, len)); 1009 size += (len + 1) * sizeof(u_short); 1010 } 1011 1012 if ((cc = write(peer->procptr->io.fd, (char *)hp, size)) < 0) { 1013 (void)sprintf(errstr, "write: %s", strerror(errno)); 1014 return (errstr); 1015 } else if (cc != size) { 1016 (void)sprintf(errstr, "short write (%d != %d)", cc, size); 1017 return (errstr); 1018 } 1019 return (NULL); 1020 } 1021 1022 /* Request periodic message output */ 1023 static struct { 1024 struct jheader jheader; 1025 struct jrequest jrequest; 1026 } reqmsg = { 1027 { putshort(JUPITER_SYNC), 0, 1028 putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), 1029 0, putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | 1030 JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 }, 1031 { 0, 0, 0, 0 } 1032 }; 1033 1034 /* An interval of zero means to output on trigger */ 1035 static void 1036 jupiter_reqmsg(register struct peer *peer, register u_int id, 1037 register u_int interval) 1038 { 1039 register struct jheader *hp; 1040 register struct jrequest *rp; 1041 register char *cp; 1042 1043 hp = &reqmsg.jheader; 1044 hp->id = putshort(id); 1045 rp = &reqmsg.jrequest; 1046 rp->trigger = putshort(interval == 0); 1047 rp->interval = putshort(interval); 1048 if ((cp = jupiter_send(peer, hp)) != NULL) 1049 jupiter_debug(peer, "jupiter_reqmsg: %u: %s\n", id, cp); 1050 } 1051 1052 /* Cancel periodic message output */ 1053 static struct jheader canmsg = { 1054 putshort(JUPITER_SYNC), 0, 0, 0, 1055 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), 1056 0 1057 }; 1058 1059 static void 1060 jupiter_canmsg(register struct peer *peer, register u_int id) 1061 { 1062 register struct jheader *hp; 1063 register char *cp; 1064 1065 hp = &canmsg; 1066 hp->id = putshort(id); 1067 if ((cp = jupiter_send(peer, hp)) != NULL) 1068 jupiter_debug(peer, "jupiter_canmsg: %u: %s\n", id, cp); 1069 } 1070 1071 /* Request a single message output */ 1072 static struct jheader reqonemsg = { 1073 putshort(JUPITER_SYNC), 0, 0, 0, 1074 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), 1075 0 1076 }; 1077 1078 static void 1079 jupiter_reqonemsg(register struct peer *peer, register u_int id) 1080 { 1081 register struct jheader *hp; 1082 register char *cp; 1083 1084 hp = &reqonemsg; 1085 hp->id = putshort(id); 1086 if ((cp = jupiter_send(peer, hp)) != NULL) 1087 jupiter_debug(peer, "jupiter_reqonemsg: %u: %s\n", id, cp); 1088 } 1089 1090 /* Set the platform dynamics */ 1091 static struct { 1092 struct jheader jheader; 1093 struct jplat jplat; 1094 } platmsg = { 1095 { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), 1096 putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, 1097 putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, 1098 { 0, 0, 0 } 1099 }; 1100 1101 static void 1102 jupiter_platform(register struct peer *peer, register u_int platform) 1103 { 1104 register struct jheader *hp; 1105 register struct jplat *pp; 1106 register char *cp; 1107 1108 hp = &platmsg.jheader; 1109 pp = &platmsg.jplat; 1110 pp->platform = putshort(platform); 1111 if ((cp = jupiter_send(peer, hp)) != NULL) 1112 jupiter_debug(peer, "jupiter_platform: %u: %s\n", platform, cp); 1113 } 1114 1115 /* Checksum "len" shorts */ 1116 static u_short 1117 jupiter_cksum(register u_short *sp, register u_int len) 1118 { 1119 register u_short sum, x; 1120 1121 sum = 0; 1122 while (len-- > 0) { 1123 x = *sp++; 1124 sum += getshort(x); 1125 } 1126 return (~sum + 1); 1127 } 1128 1129 /* Return the size of the next message (or zero if we don't have it all yet) */ 1130 static int 1131 jupiter_recv(register struct peer *peer) 1132 { 1133 register int n, len, size, cc; 1134 register struct refclockproc *pp; 1135 register struct jupiterunit *up; 1136 register struct jheader *hp; 1137 register u_char *bp; 1138 register u_short *sp; 1139 1140 pp = peer->procptr; 1141 up = (struct jupiterunit *)pp->unitptr; 1142 1143 /* Must have at least a header's worth */ 1144 cc = sizeof(*hp); 1145 size = up->ssize; 1146 if (size < cc) 1147 return (0); 1148 1149 /* Search for the sync short if missing */ 1150 sp = up->sbuf; 1151 hp = (struct jheader *)sp; 1152 if (getshort(hp->sync) != JUPITER_SYNC) { 1153 /* Wasn't at the front, sync up */ 1154 jupiter_debug(peer, "syncing"); 1155 bp = (u_char *)sp; 1156 n = size; 1157 while (n >= 2) { 1158 if (bp[0] != (JUPITER_SYNC & 0xff)) { 1159 jupiter_debug(peer, "{0x%x}", bp[0]); 1160 ++bp; 1161 --n; 1162 continue; 1163 } 1164 if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) 1165 break; 1166 jupiter_debug(peer, "{0x%x 0x%x}", bp[0], bp[1]); 1167 bp += 2; 1168 n -= 2; 1169 } 1170 jupiter_debug(peer, "\n"); 1171 /* Shuffle data to front of input buffer */ 1172 if (n > 0) 1173 memcpy(sp, bp, n); 1174 size = n; 1175 up->ssize = size; 1176 if (size < cc || hp->sync != JUPITER_SYNC) 1177 return (0); 1178 } 1179 1180 if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != 1181 getshort(hp->hsum)) { 1182 jupiter_debug(peer, "jupiter_recv: bad header checksum!\n"); 1183 /* This is drastic but checksum errors should be rare */ 1184 up->ssize = 0; 1185 return (0); 1186 } 1187 1188 /* Check for a payload */ 1189 len = getshort(hp->len); 1190 if (len > 0) { 1191 n = (len + 1) * sizeof(u_short); 1192 /* Not enough data yet */ 1193 if (size < cc + n) 1194 return (0); 1195 1196 /* Check payload checksum */ 1197 sp = (u_short *)(hp + 1); 1198 if (jupiter_cksum(sp, len) != getshort(sp[len])) { 1199 jupiter_debug(peer, 1200 "jupiter_recv: bad payload checksum!\n"); 1201 /* This is drastic but checksum errors should be rare */ 1202 up->ssize = 0; 1203 return (0); 1204 } 1205 cc += n; 1206 } 1207 return (cc); 1208 } 1209 1210 static int 1211 jupiter_ttyinit(register struct peer *peer, register int fd) 1212 { 1213 struct termios termios; 1214 1215 memset((char *)&termios, 0, sizeof(termios)); 1216 if (cfsetispeed(&termios, B9600) < 0 || 1217 cfsetospeed(&termios, B9600) < 0) { 1218 jupiter_debug(peer, 1219 "jupiter_ttyinit: cfsetispeed/cfgetospeed: %s\n", 1220 strerror(errno)); 1221 return (0); 1222 } 1223 #ifdef HAVE_CFMAKERAW 1224 cfmakeraw(&termios); 1225 #else 1226 termios.c_iflag &= ~(IMAXBEL | IXOFF | INPCK | BRKINT | PARMRK | 1227 ISTRIP | INLCR | IGNCR | ICRNL | IXON | IGNPAR); 1228 termios.c_iflag |= IGNBRK; 1229 termios.c_oflag &= ~OPOST; 1230 termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | 1231 IEXTEN | NOFLSH | TOSTOP | PENDIN); 1232 termios.c_cflag &= ~(CSIZE | PARENB); 1233 termios.c_cflag |= CS8 | CREAD; 1234 termios.c_cc[VMIN] = 1; 1235 #endif 1236 termios.c_cflag |= CLOCAL; 1237 if (tcsetattr(fd, TCSANOW, &termios) < 0) { 1238 jupiter_debug(peer, "jupiter_ttyinit: tcsetattr: %s\n", 1239 strerror(errno)); 1240 return (0); 1241 } 1242 1243 #ifdef TIOCSPPS 1244 if (ioctl(fd, TIOCSPPS, (char *)&fdpps) < 0) { 1245 jupiter_debug(peer, "jupiter_ttyinit: TIOCSPPS: %s\n", 1246 strerror(errno)); 1247 return (0); 1248 } 1249 #endif 1250 #ifdef I_PUSH 1251 if (ioctl(fd, I_PUSH, "ppsclock") < 0) { 1252 jupiter_debug(peer, "jupiter_ttyinit: push ppsclock: %s\n", 1253 strerror(errno)); 1254 return (0); 1255 } 1256 #endif 1257 1258 return (1); 1259 } 1260 1261 #else /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ 1262 int refclock_jupiter_bs; 1263 #endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ 1264