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