1*eabc0478Schristos /* $NetBSD: ntp_refclock.c,v 1.15 2024/08/18 20:47:17 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_refclock - processing support for reference clocks 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel # include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #include "ntpd.h" 11abb0f93cSkardel #include "ntp_io.h" 12abb0f93cSkardel #include "ntp_unixtime.h" 13abb0f93cSkardel #include "ntp_tty.h" 14abb0f93cSkardel #include "ntp_refclock.h" 15*eabc0478Schristos #include "ntp_clockdev.h" 16abb0f93cSkardel #include "ntp_stdlib.h" 173123f114Skardel #include "ntp_assert.h" 18cdfa2a7eSchristos #include "timespecops.h" 19abb0f93cSkardel 20abb0f93cSkardel #include <stdio.h> 21abb0f93cSkardel 22abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H 23abb0f93cSkardel # include <sys/ioctl.h> 24abb0f93cSkardel #endif /* HAVE_SYS_IOCTL_H */ 25abb0f93cSkardel 26abb0f93cSkardel #ifdef REFCLOCK 27abb0f93cSkardel 28abb0f93cSkardel #ifdef KERNEL_PLL 29abb0f93cSkardel #include "ntp_syscall.h" 30abb0f93cSkardel #endif /* KERNEL_PLL */ 31abb0f93cSkardel 32abb0f93cSkardel #ifdef HAVE_PPSAPI 33abb0f93cSkardel #include "ppsapi_timepps.h" 34abb0f93cSkardel #include "refclock_atom.h" 35abb0f93cSkardel #endif /* HAVE_PPSAPI */ 36abb0f93cSkardel 37abb0f93cSkardel /* 38abb0f93cSkardel * Reference clock support is provided here by maintaining the fiction 39abb0f93cSkardel * that the clock is actually a peer. As no packets are exchanged with 40abb0f93cSkardel * a reference clock, however, we replace the transmit, receive and 41abb0f93cSkardel * packet procedures with separate code to simulate them. Routines 42abb0f93cSkardel * refclock_transmit() and refclock_receive() maintain the peer 43abb0f93cSkardel * variables in a state analogous to an actual peer and pass reference 44abb0f93cSkardel * clock data on through the filters. Routines refclock_peer() and 45abb0f93cSkardel * refclock_unpeer() are called to initialize and terminate reference 46abb0f93cSkardel * clock associations. A set of utility routines is included to open 472950cc38Schristos * serial devices, process sample data, and to perform various debugging 482950cc38Schristos * functions. 49abb0f93cSkardel * 50abb0f93cSkardel * The main interface used by these routines is the refclockproc 51abb0f93cSkardel * structure, which contains for most drivers the decimal equivalants 52abb0f93cSkardel * of the year, day, month, hour, second and millisecond/microsecond 53abb0f93cSkardel * decoded from the ASCII timecode. Additional information includes 54abb0f93cSkardel * the receive timestamp, exception report, statistics tallies, etc. 55abb0f93cSkardel * In addition, there may be a driver-specific unit structure used for 56abb0f93cSkardel * local control of the device. 57abb0f93cSkardel * 58abb0f93cSkardel * The support routines are passed a pointer to the peer structure, 59abb0f93cSkardel * which is used for all peer-specific processing and contains a 60abb0f93cSkardel * pointer to the refclockproc structure, which in turn contains a 61abb0f93cSkardel * pointer to the unit structure, if used. The peer structure is 62abb0f93cSkardel * identified by an interface address in the dotted quad form 63abb0f93cSkardel * 127.127.t.u, where t is the clock type and u the unit. 64abb0f93cSkardel */ 65abb0f93cSkardel #define FUDGEFAC .1 /* fudge correction factor */ 66abb0f93cSkardel #define LF 0x0a /* ASCII LF */ 67abb0f93cSkardel 68abb0f93cSkardel int cal_enable; /* enable refclock calibrate */ 69abb0f93cSkardel 70abb0f93cSkardel /* 71abb0f93cSkardel * Forward declarations 72abb0f93cSkardel */ 73abb0f93cSkardel static int refclock_cmpl_fp (const void *, const void *); 74abb0f93cSkardel static int refclock_sample (struct refclockproc *); 752950cc38Schristos static int refclock_ioctl(int, u_int); 76cdfa2a7eSchristos static void refclock_checkburst(struct peer *, struct refclockproc *); 77abb0f93cSkardel 78cdfa2a7eSchristos /* circular buffer functions 79cdfa2a7eSchristos * 80cdfa2a7eSchristos * circular buffer management comes in two flovours: 81cdfa2a7eSchristos * for powers of two, and all others. 82cdfa2a7eSchristos */ 83cdfa2a7eSchristos 84cdfa2a7eSchristos #if MAXSTAGE & (MAXSTAGE - 1) 85cdfa2a7eSchristos 86cdfa2a7eSchristos static void clk_add_sample( 87cdfa2a7eSchristos struct refclockproc * const pp, 88cdfa2a7eSchristos double sv 89cdfa2a7eSchristos ) 90cdfa2a7eSchristos { 91cdfa2a7eSchristos pp->coderecv = (pp->coderecv + 1) % MAXSTAGE; 92cdfa2a7eSchristos if (pp->coderecv == pp->codeproc) 93cdfa2a7eSchristos pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 94cdfa2a7eSchristos pp->filter[pp->coderecv] = sv; 95cdfa2a7eSchristos } 96cdfa2a7eSchristos 97cdfa2a7eSchristos static double clk_pop_sample( 98cdfa2a7eSchristos struct refclockproc * const pp 99cdfa2a7eSchristos ) 100cdfa2a7eSchristos { 101cdfa2a7eSchristos if (pp->coderecv == pp->codeproc) 102cdfa2a7eSchristos return 0; /* Maybe a NaN would be better? */ 103cdfa2a7eSchristos pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 104cdfa2a7eSchristos return pp->filter[pp->codeproc]; 105cdfa2a7eSchristos } 106cdfa2a7eSchristos 107cdfa2a7eSchristos static inline u_int clk_cnt_sample( 108cdfa2a7eSchristos struct refclockproc * const pp 109cdfa2a7eSchristos ) 110cdfa2a7eSchristos { 111cdfa2a7eSchristos u_int retv = pp->coderecv - pp->codeproc; 112cdfa2a7eSchristos if (retv > MAXSTAGE) 113cdfa2a7eSchristos retv += MAXSTAGE; 114cdfa2a7eSchristos return retv; 115cdfa2a7eSchristos } 116cdfa2a7eSchristos 117cdfa2a7eSchristos #else 118cdfa2a7eSchristos 119cdfa2a7eSchristos static inline void clk_add_sample( 120cdfa2a7eSchristos struct refclockproc * const pp, 121cdfa2a7eSchristos double sv 122cdfa2a7eSchristos ) 123cdfa2a7eSchristos { 124cdfa2a7eSchristos pp->coderecv = (pp->coderecv + 1) & (MAXSTAGE - 1); 125cdfa2a7eSchristos if (pp->coderecv == pp->codeproc) 126cdfa2a7eSchristos pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1); 127cdfa2a7eSchristos pp->filter[pp->coderecv] = sv; 128cdfa2a7eSchristos } 129cdfa2a7eSchristos 130cdfa2a7eSchristos static inline double clk_pop_sample( 131cdfa2a7eSchristos struct refclockproc * const pp 132cdfa2a7eSchristos ) 133cdfa2a7eSchristos { 134cdfa2a7eSchristos if (pp->coderecv == pp->codeproc) 135cdfa2a7eSchristos return 0; /* Maybe a NaN would be better? */ 136cdfa2a7eSchristos pp->codeproc = (pp->codeproc + 1) & (MAXSTAGE - 1); 137cdfa2a7eSchristos return pp->filter[pp->codeproc]; 138cdfa2a7eSchristos } 139cdfa2a7eSchristos 140cdfa2a7eSchristos static inline u_int clk_cnt_sample( 141cdfa2a7eSchristos struct refclockproc * const pp 142cdfa2a7eSchristos ) 143cdfa2a7eSchristos { 144cdfa2a7eSchristos return (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 145cdfa2a7eSchristos } 146cdfa2a7eSchristos 147cdfa2a7eSchristos #endif 148abb0f93cSkardel 149abb0f93cSkardel /* 150abb0f93cSkardel * refclock_report - note the occurance of an event 151abb0f93cSkardel * 152abb0f93cSkardel * This routine presently just remembers the report and logs it, but 153abb0f93cSkardel * does nothing heroic for the trap handler. It tries to be a good 154abb0f93cSkardel * citizen and bothers the system log only if things change. 155abb0f93cSkardel */ 156abb0f93cSkardel void 157abb0f93cSkardel refclock_report( 158abb0f93cSkardel struct peer *peer, 159abb0f93cSkardel int code 160abb0f93cSkardel ) 161abb0f93cSkardel { 162abb0f93cSkardel struct refclockproc *pp; 163abb0f93cSkardel 164abb0f93cSkardel pp = peer->procptr; 165abb0f93cSkardel if (pp == NULL) 166abb0f93cSkardel return; 167abb0f93cSkardel 168abb0f93cSkardel switch (code) { 169abb0f93cSkardel 170abb0f93cSkardel case CEVNT_TIMEOUT: 171abb0f93cSkardel pp->noreply++; 172abb0f93cSkardel break; 173abb0f93cSkardel 174abb0f93cSkardel case CEVNT_BADREPLY: 175abb0f93cSkardel pp->badformat++; 176abb0f93cSkardel break; 177abb0f93cSkardel 178abb0f93cSkardel case CEVNT_FAULT: 179abb0f93cSkardel break; 180abb0f93cSkardel 181abb0f93cSkardel case CEVNT_BADDATE: 182abb0f93cSkardel case CEVNT_BADTIME: 183abb0f93cSkardel pp->baddata++; 184abb0f93cSkardel break; 185abb0f93cSkardel 186abb0f93cSkardel default: 187abb0f93cSkardel /* ignore others */ 188abb0f93cSkardel break; 189abb0f93cSkardel } 19079045f13Schristos if ((code != CEVNT_NOMINAL) && (pp->lastevent < 15)) 191abb0f93cSkardel pp->lastevent++; 192abb0f93cSkardel if (pp->currentstatus != code) { 193abb0f93cSkardel pp->currentstatus = (u_char)code; 194abb0f93cSkardel report_event(PEVNT_CLOCK, peer, ceventstr(code)); 195abb0f93cSkardel } 196abb0f93cSkardel } 197abb0f93cSkardel 198abb0f93cSkardel 199abb0f93cSkardel /* 200abb0f93cSkardel * init_refclock - initialize the reference clock drivers 201abb0f93cSkardel * 202abb0f93cSkardel * This routine calls each of the drivers in turn to initialize internal 203abb0f93cSkardel * variables, if necessary. Most drivers have nothing to say at this 204abb0f93cSkardel * point. 205abb0f93cSkardel */ 206abb0f93cSkardel void 207abb0f93cSkardel init_refclock(void) 208abb0f93cSkardel { 209abb0f93cSkardel int i; 210abb0f93cSkardel 211abb0f93cSkardel for (i = 0; i < (int)num_refclock_conf; i++) 212abb0f93cSkardel if (refclock_conf[i]->clock_init != noentry) 213abb0f93cSkardel (refclock_conf[i]->clock_init)(); 214abb0f93cSkardel } 215abb0f93cSkardel 216abb0f93cSkardel 217abb0f93cSkardel /* 218abb0f93cSkardel * refclock_newpeer - initialize and start a reference clock 219abb0f93cSkardel * 220abb0f93cSkardel * This routine allocates and initializes the interface structure which 221abb0f93cSkardel * supports a reference clock in the form of an ordinary NTP peer. A 222abb0f93cSkardel * driver-specific support routine completes the initialization, if 223abb0f93cSkardel * used. Default peer variables which identify the clock and establish 224abb0f93cSkardel * its reference ID and stratum are set here. It returns one if success 225abb0f93cSkardel * and zero if the clock address is invalid or already running, 226abb0f93cSkardel * insufficient resources are available or the driver declares a bum 227abb0f93cSkardel * rap. 228abb0f93cSkardel */ 229abb0f93cSkardel int 230abb0f93cSkardel refclock_newpeer( 231abb0f93cSkardel struct peer *peer /* peer structure pointer */ 232abb0f93cSkardel ) 233abb0f93cSkardel { 234abb0f93cSkardel struct refclockproc *pp; 235abb0f93cSkardel u_char clktype; 236abb0f93cSkardel int unit; 237abb0f93cSkardel 238abb0f93cSkardel /* 239abb0f93cSkardel * Check for valid clock address. If already running, shut it 240abb0f93cSkardel * down first. 241abb0f93cSkardel */ 242abb0f93cSkardel if (!ISREFCLOCKADR(&peer->srcadr)) { 243abb0f93cSkardel msyslog(LOG_ERR, 244abb0f93cSkardel "refclock_newpeer: clock address %s invalid", 245abb0f93cSkardel stoa(&peer->srcadr)); 246abb0f93cSkardel return (0); 247abb0f93cSkardel } 248abb0f93cSkardel clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 249abb0f93cSkardel unit = REFCLOCKUNIT(&peer->srcadr); 250abb0f93cSkardel if (clktype >= num_refclock_conf || 251abb0f93cSkardel refclock_conf[clktype]->clock_start == noentry) { 252abb0f93cSkardel msyslog(LOG_ERR, 253abb0f93cSkardel "refclock_newpeer: clock type %d invalid\n", 254abb0f93cSkardel clktype); 255abb0f93cSkardel return (0); 256abb0f93cSkardel } 257abb0f93cSkardel 258abb0f93cSkardel /* 259abb0f93cSkardel * Allocate and initialize interface structure 260abb0f93cSkardel */ 2612950cc38Schristos pp = emalloc_zero(sizeof(*pp)); 262abb0f93cSkardel peer->procptr = pp; 263abb0f93cSkardel 264abb0f93cSkardel /* 265abb0f93cSkardel * Initialize structures 266abb0f93cSkardel */ 267abb0f93cSkardel peer->refclktype = clktype; 268abb0f93cSkardel peer->refclkunit = (u_char)unit; 269abb0f93cSkardel peer->flags |= FLAG_REFCLOCK; 270abb0f93cSkardel peer->leap = LEAP_NOTINSYNC; 271abb0f93cSkardel peer->stratum = STRATUM_REFCLOCK; 272abb0f93cSkardel peer->ppoll = peer->maxpoll; 273abb0f93cSkardel pp->type = clktype; 2742950cc38Schristos pp->conf = refclock_conf[clktype]; 275abb0f93cSkardel pp->timestarted = current_time; 2762950cc38Schristos pp->io.fd = -1; 277abb0f93cSkardel 278abb0f93cSkardel /* 279abb0f93cSkardel * Set peer.pmode based on the hmode. For appearances only. 280abb0f93cSkardel */ 281abb0f93cSkardel switch (peer->hmode) { 282abb0f93cSkardel case MODE_ACTIVE: 283abb0f93cSkardel peer->pmode = MODE_PASSIVE; 284abb0f93cSkardel break; 285abb0f93cSkardel 286abb0f93cSkardel default: 287abb0f93cSkardel peer->pmode = MODE_SERVER; 288abb0f93cSkardel break; 289abb0f93cSkardel } 290abb0f93cSkardel 291abb0f93cSkardel /* 292abb0f93cSkardel * Do driver dependent initialization. The above defaults 293abb0f93cSkardel * can be wiggled, then finish up for consistency. 294abb0f93cSkardel */ 295abb0f93cSkardel if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { 296abb0f93cSkardel refclock_unpeer(peer); 297abb0f93cSkardel return (0); 298abb0f93cSkardel } 299abb0f93cSkardel peer->refid = pp->refid; 300abb0f93cSkardel return (1); 301abb0f93cSkardel } 302abb0f93cSkardel 303abb0f93cSkardel 304abb0f93cSkardel /* 305abb0f93cSkardel * refclock_unpeer - shut down a clock 306abb0f93cSkardel */ 307abb0f93cSkardel void 308abb0f93cSkardel refclock_unpeer( 309abb0f93cSkardel struct peer *peer /* peer structure pointer */ 310abb0f93cSkardel ) 311abb0f93cSkardel { 312abb0f93cSkardel u_char clktype; 313abb0f93cSkardel int unit; 314abb0f93cSkardel 315abb0f93cSkardel /* 316abb0f93cSkardel * Wiggle the driver to release its resources, then give back 317abb0f93cSkardel * the interface structure. 318abb0f93cSkardel */ 319abb0f93cSkardel if (NULL == peer->procptr) 320abb0f93cSkardel return; 321abb0f93cSkardel 322abb0f93cSkardel clktype = peer->refclktype; 323abb0f93cSkardel unit = peer->refclkunit; 324abb0f93cSkardel if (refclock_conf[clktype]->clock_shutdown != noentry) 325abb0f93cSkardel (refclock_conf[clktype]->clock_shutdown)(unit, peer); 326abb0f93cSkardel free(peer->procptr); 327abb0f93cSkardel peer->procptr = NULL; 328abb0f93cSkardel } 329abb0f93cSkardel 330abb0f93cSkardel 331abb0f93cSkardel /* 332abb0f93cSkardel * refclock_timer - called once per second for housekeeping. 333abb0f93cSkardel */ 334abb0f93cSkardel void 335abb0f93cSkardel refclock_timer( 3362950cc38Schristos struct peer *p 337abb0f93cSkardel ) 338abb0f93cSkardel { 3392950cc38Schristos struct refclockproc * pp; 340abb0f93cSkardel int unit; 341abb0f93cSkardel 3422950cc38Schristos unit = p->refclkunit; 3432950cc38Schristos pp = p->procptr; 3442950cc38Schristos if (pp->conf->clock_timer != noentry) 3452950cc38Schristos (*pp->conf->clock_timer)(unit, p); 3462950cc38Schristos if (pp->action != NULL && pp->nextaction <= current_time) 3472950cc38Schristos (*pp->action)(p); 348abb0f93cSkardel } 349abb0f93cSkardel 350abb0f93cSkardel 351abb0f93cSkardel /* 352abb0f93cSkardel * refclock_transmit - simulate the transmit procedure 353abb0f93cSkardel * 354abb0f93cSkardel * This routine implements the NTP transmit procedure for a reference 355abb0f93cSkardel * clock. This provides a mechanism to call the driver at the NTP poll 356abb0f93cSkardel * interval, as well as provides a reachability mechanism to detect a 357abb0f93cSkardel * broken radio or other madness. 358abb0f93cSkardel */ 359abb0f93cSkardel void 360abb0f93cSkardel refclock_transmit( 361abb0f93cSkardel struct peer *peer /* peer structure pointer */ 362abb0f93cSkardel ) 363abb0f93cSkardel { 364abb0f93cSkardel u_char clktype; 365abb0f93cSkardel int unit; 366abb0f93cSkardel 367abb0f93cSkardel clktype = peer->refclktype; 368abb0f93cSkardel unit = peer->refclkunit; 369abb0f93cSkardel peer->sent++; 370abb0f93cSkardel get_systime(&peer->xmt); 371abb0f93cSkardel 372abb0f93cSkardel /* 373abb0f93cSkardel * This is a ripoff of the peer transmit routine, but 374abb0f93cSkardel * specialized for reference clocks. We do a little less 375abb0f93cSkardel * protocol here and call the driver-specific transmit routine. 376abb0f93cSkardel */ 377abb0f93cSkardel if (peer->burst == 0) { 378abb0f93cSkardel u_char oreach; 379abb0f93cSkardel #ifdef DEBUG 380abb0f93cSkardel if (debug) 381abb0f93cSkardel printf("refclock_transmit: at %ld %s\n", 382abb0f93cSkardel current_time, stoa(&(peer->srcadr))); 383abb0f93cSkardel #endif 384abb0f93cSkardel 385abb0f93cSkardel /* 386abb0f93cSkardel * Update reachability and poll variables like the 387abb0f93cSkardel * network code. 388abb0f93cSkardel */ 389abb0f93cSkardel oreach = peer->reach & 0xfe; 390abb0f93cSkardel peer->reach <<= 1; 391abb0f93cSkardel if (!(peer->reach & 0x0f)) 392abb0f93cSkardel clock_filter(peer, 0., 0., MAXDISPERSE); 393abb0f93cSkardel peer->outdate = current_time; 394abb0f93cSkardel if (!peer->reach) { 395abb0f93cSkardel if (oreach) { 396abb0f93cSkardel report_event(PEVNT_UNREACH, peer, NULL); 397abb0f93cSkardel peer->timereachable = current_time; 398abb0f93cSkardel } 399abb0f93cSkardel } else { 400abb0f93cSkardel if (peer->flags & FLAG_BURST) 401abb0f93cSkardel peer->burst = NSTAGE; 402abb0f93cSkardel } 403abb0f93cSkardel } else { 404abb0f93cSkardel peer->burst--; 405abb0f93cSkardel } 406cdfa2a7eSchristos peer->procptr->inpoll = TRUE; 407abb0f93cSkardel if (refclock_conf[clktype]->clock_poll != noentry) 408abb0f93cSkardel (refclock_conf[clktype]->clock_poll)(unit, peer); 409cdfa2a7eSchristos poll_update(peer, peer->hpoll, 0); 410abb0f93cSkardel } 411abb0f93cSkardel 412abb0f93cSkardel 413abb0f93cSkardel /* 414abb0f93cSkardel * Compare two doubles - used with qsort() 415abb0f93cSkardel */ 416abb0f93cSkardel static int 417abb0f93cSkardel refclock_cmpl_fp( 418abb0f93cSkardel const void *p1, 419abb0f93cSkardel const void *p2 420abb0f93cSkardel ) 421abb0f93cSkardel { 422abb0f93cSkardel const double *dp1 = (const double *)p1; 423abb0f93cSkardel const double *dp2 = (const double *)p2; 424abb0f93cSkardel 425abb0f93cSkardel if (*dp1 < *dp2) 4263123f114Skardel return -1; 427abb0f93cSkardel if (*dp1 > *dp2) 4283123f114Skardel return 1; 4293123f114Skardel return 0; 430abb0f93cSkardel } 431abb0f93cSkardel 432cdfa2a7eSchristos /* 433cdfa2a7eSchristos * Get number of available samples 434cdfa2a7eSchristos */ 435cdfa2a7eSchristos int 436cdfa2a7eSchristos refclock_samples_avail( 437cdfa2a7eSchristos struct refclockproc const * pp 438cdfa2a7eSchristos ) 439cdfa2a7eSchristos { 440cdfa2a7eSchristos u_int na; 441cdfa2a7eSchristos 442cdfa2a7eSchristos # if MAXSTAGE & (MAXSTAGE - 1) 443cdfa2a7eSchristos 444cdfa2a7eSchristos na = pp->coderecv - pp->codeproc; 445cdfa2a7eSchristos if (na > MAXSTAGE) 446cdfa2a7eSchristos na += MAXSTAGE; 447cdfa2a7eSchristos 448cdfa2a7eSchristos # else 449cdfa2a7eSchristos 450cdfa2a7eSchristos na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 451cdfa2a7eSchristos 452cdfa2a7eSchristos # endif 453cdfa2a7eSchristos return na; 454cdfa2a7eSchristos } 455cdfa2a7eSchristos 456cdfa2a7eSchristos /* 457cdfa2a7eSchristos * Expire (remove) samples from the tail (oldest samples removed) 458cdfa2a7eSchristos * 459cdfa2a7eSchristos * Returns number of samples deleted 460cdfa2a7eSchristos */ 461cdfa2a7eSchristos int 462cdfa2a7eSchristos refclock_samples_expire( 463cdfa2a7eSchristos struct refclockproc * pp, 464cdfa2a7eSchristos int nd 465cdfa2a7eSchristos ) 466cdfa2a7eSchristos { 467cdfa2a7eSchristos u_int na; 468cdfa2a7eSchristos 469cdfa2a7eSchristos if (nd <= 0) 470cdfa2a7eSchristos return 0; 471cdfa2a7eSchristos 472cdfa2a7eSchristos # if MAXSTAGE & (MAXSTAGE - 1) 473cdfa2a7eSchristos 474cdfa2a7eSchristos na = pp->coderecv - pp->codeproc; 475cdfa2a7eSchristos if (na > MAXSTAGE) 476cdfa2a7eSchristos na += MAXSTAGE; 477cdfa2a7eSchristos if ((u_int)nd < na) 478cdfa2a7eSchristos nd = na; 479cdfa2a7eSchristos pp->codeproc = (pp->codeproc + nd) % MAXSTAGE; 480cdfa2a7eSchristos 481cdfa2a7eSchristos # else 482cdfa2a7eSchristos 483cdfa2a7eSchristos na = (pp->coderecv - pp->codeproc) & (MAXSTAGE - 1); 484cdfa2a7eSchristos if ((u_int)nd > na) 485cdfa2a7eSchristos nd = (int)na; 486cdfa2a7eSchristos pp->codeproc = (pp->codeproc + nd) & (MAXSTAGE - 1); 487cdfa2a7eSchristos 488cdfa2a7eSchristos # endif 489cdfa2a7eSchristos return nd; 490cdfa2a7eSchristos } 491abb0f93cSkardel 492abb0f93cSkardel /* 493abb0f93cSkardel * refclock_process_offset - update median filter 494abb0f93cSkardel * 495abb0f93cSkardel * This routine uses the given offset and timestamps to construct a new 496abb0f93cSkardel * entry in the median filter circular buffer. Samples that overflow the 497abb0f93cSkardel * filter are quietly discarded. 498abb0f93cSkardel */ 499abb0f93cSkardel void 500abb0f93cSkardel refclock_process_offset( 501abb0f93cSkardel struct refclockproc *pp, /* refclock structure pointer */ 502abb0f93cSkardel l_fp lasttim, /* last timecode timestamp */ 503abb0f93cSkardel l_fp lastrec, /* last receive timestamp */ 504abb0f93cSkardel double fudge 505abb0f93cSkardel ) 506abb0f93cSkardel { 507abb0f93cSkardel l_fp lftemp; 508abb0f93cSkardel double doffset; 509abb0f93cSkardel 510abb0f93cSkardel pp->lastrec = lastrec; 511abb0f93cSkardel lftemp = lasttim; 512abb0f93cSkardel L_SUB(&lftemp, &lastrec); 513abb0f93cSkardel LFPTOD(&lftemp, doffset); 514cdfa2a7eSchristos clk_add_sample(pp, doffset + fudge); 515cdfa2a7eSchristos refclock_checkburst(pp->io.srcclock, pp); 516abb0f93cSkardel } 517abb0f93cSkardel 518abb0f93cSkardel 519abb0f93cSkardel /* 520abb0f93cSkardel * refclock_process - process a sample from the clock 521abb0f93cSkardel * refclock_process_f - refclock_process with other than time1 fudge 522abb0f93cSkardel * 523abb0f93cSkardel * This routine converts the timecode in the form days, hours, minutes, 524abb0f93cSkardel * seconds and milliseconds/microseconds to internal timestamp format, 525abb0f93cSkardel * then constructs a new entry in the median filter circular buffer. 526abb0f93cSkardel * Return success (1) if the data are correct and consistent with the 527cdfa2a7eSchristos * conventional calendar. 528abb0f93cSkardel * 529abb0f93cSkardel * Important for PPS users: Normally, the pp->lastrec is set to the 530abb0f93cSkardel * system time when the on-time character is received and the pp->year, 531abb0f93cSkardel * ..., pp->second decoded and the seconds fraction pp->nsec in 532abb0f93cSkardel * nanoseconds). When a PPS offset is available, pp->nsec is forced to 533abb0f93cSkardel * zero and the fraction for pp->lastrec is set to the PPS offset. 534abb0f93cSkardel */ 535abb0f93cSkardel int 536abb0f93cSkardel refclock_process_f( 537abb0f93cSkardel struct refclockproc *pp, /* refclock structure pointer */ 538abb0f93cSkardel double fudge 539abb0f93cSkardel ) 540abb0f93cSkardel { 541abb0f93cSkardel l_fp offset, ltemp; 542abb0f93cSkardel 543abb0f93cSkardel /* 544abb0f93cSkardel * Compute the timecode timestamp from the days, hours, minutes, 545abb0f93cSkardel * seconds and milliseconds/microseconds of the timecode. Use 546abb0f93cSkardel * clocktime() for the aggregate seconds and the msec/usec for 547abb0f93cSkardel * the fraction, when present. Note that this code relies on the 548abb0f93cSkardel * file system time for the years and does not use the years of 549abb0f93cSkardel * the timecode. 550abb0f93cSkardel */ 551abb0f93cSkardel if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 552abb0f93cSkardel pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 553abb0f93cSkardel return (0); 554abb0f93cSkardel 555abb0f93cSkardel offset.l_uf = 0; 556abb0f93cSkardel DTOLFP(pp->nsec / 1e9, <emp); 557abb0f93cSkardel L_ADD(&offset, <emp); 558abb0f93cSkardel refclock_process_offset(pp, offset, pp->lastrec, fudge); 559abb0f93cSkardel return (1); 560abb0f93cSkardel } 561abb0f93cSkardel 562abb0f93cSkardel 563abb0f93cSkardel int 564abb0f93cSkardel refclock_process( 565abb0f93cSkardel struct refclockproc *pp /* refclock structure pointer */ 566abb0f93cSkardel ) 567abb0f93cSkardel { 568abb0f93cSkardel return refclock_process_f(pp, pp->fudgetime1); 569abb0f93cSkardel } 570abb0f93cSkardel 571abb0f93cSkardel 572abb0f93cSkardel /* 573abb0f93cSkardel * refclock_sample - process a pile of samples from the clock 574abb0f93cSkardel * 575abb0f93cSkardel * This routine implements a recursive median filter to suppress spikes 576abb0f93cSkardel * in the data, as well as determine a performance statistic. It 577abb0f93cSkardel * calculates the mean offset and RMS jitter. A time adjustment 578abb0f93cSkardel * fudgetime1 can be added to the final offset to compensate for various 579abb0f93cSkardel * systematic errors. The routine returns the number of samples 580abb0f93cSkardel * processed, which could be zero. 581abb0f93cSkardel */ 582abb0f93cSkardel static int 583abb0f93cSkardel refclock_sample( 584abb0f93cSkardel struct refclockproc *pp /* refclock structure pointer */ 585abb0f93cSkardel ) 586abb0f93cSkardel { 5873123f114Skardel size_t i, j, k, m, n; 588abb0f93cSkardel double off[MAXSTAGE]; 589abb0f93cSkardel 590abb0f93cSkardel /* 591abb0f93cSkardel * Copy the raw offsets and sort into ascending order. Don't do 592abb0f93cSkardel * anything if the buffer is empty. 593abb0f93cSkardel */ 594abb0f93cSkardel n = 0; 595cdfa2a7eSchristos while (pp->codeproc != pp->coderecv) 596cdfa2a7eSchristos off[n++] = clk_pop_sample(pp); 597abb0f93cSkardel if (n == 0) 598abb0f93cSkardel return (0); 599abb0f93cSkardel 600abb0f93cSkardel if (n > 1) 6012950cc38Schristos qsort(off, n, sizeof(off[0]), refclock_cmpl_fp); 602abb0f93cSkardel 603abb0f93cSkardel /* 604abb0f93cSkardel * Reject the furthest from the median of the samples until 605abb0f93cSkardel * approximately 60 percent of the samples remain. 606*eabc0478Schristos * 607*eabc0478Schristos * [Bug 3672] The elimination is now based on the proper 608*eabc0478Schristos * definition of the median. The true median is not calculated 609*eabc0478Schristos * directly, though. 610abb0f93cSkardel */ 611abb0f93cSkardel i = 0; j = n; 612abb0f93cSkardel m = n - (n * 4) / 10; 613*eabc0478Schristos while ((k = j - i) > m) { 614*eabc0478Schristos k = (k - 1) >> 1; 615*eabc0478Schristos if ((off[j - 1] - off[j - k - 1]) < (off[i + k] - off[i])) 616abb0f93cSkardel i++; /* reject low end */ 617abb0f93cSkardel else 618abb0f93cSkardel j--; /* reject high end */ 619abb0f93cSkardel } 620abb0f93cSkardel 621abb0f93cSkardel /* 622abb0f93cSkardel * Determine the offset and jitter. 623abb0f93cSkardel */ 62450c1baceSchristos pp->offset = off[i]; 625abb0f93cSkardel pp->jitter = 0; 62650c1baceSchristos for (k = i + 1; k < j; k++) { 627abb0f93cSkardel pp->offset += off[k]; 628abb0f93cSkardel pp->jitter += SQUARE(off[k] - off[k - 1]); 629abb0f93cSkardel } 630abb0f93cSkardel pp->offset /= m; 63150c1baceSchristos m -= (m > 1); /* only (m-1) terms attribute to jitter! */ 632abb0f93cSkardel pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); 633cdfa2a7eSchristos 634cdfa2a7eSchristos /* 635cdfa2a7eSchristos * If the source has a jitter that cannot be estimated, because 636cdfa2a7eSchristos * it is not statistic jitter, the source will be detected as 637cdfa2a7eSchristos * falseticker sooner or later. Enforcing a minimal jitter value 638cdfa2a7eSchristos * avoids a too low estimation while still detecting higher jitter. 639cdfa2a7eSchristos * 640cdfa2a7eSchristos * Note that this changes the refclock samples and ends up in the 641cdfa2a7eSchristos * clock dispersion, not the clock jitter, despite being called 642cdfa2a7eSchristos * jitter. To see the modified values, check the NTP clock variable 643cdfa2a7eSchristos * "filtdisp", not "jitter". 644cdfa2a7eSchristos */ 645cdfa2a7eSchristos pp->jitter = max(pp->jitter, pp->fudgeminjitter); 646cdfa2a7eSchristos 647abb0f93cSkardel #ifdef DEBUG 648abb0f93cSkardel if (debug) 649abb0f93cSkardel printf( 650abb0f93cSkardel "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 651a2545411Skardel (int)n, pp->offset, pp->disp, pp->jitter); 652abb0f93cSkardel #endif 6533123f114Skardel return (int)n; 654abb0f93cSkardel } 655abb0f93cSkardel 656abb0f93cSkardel 657abb0f93cSkardel /* 658abb0f93cSkardel * refclock_receive - simulate the receive and packet procedures 659abb0f93cSkardel * 660abb0f93cSkardel * This routine simulates the NTP receive and packet procedures for a 661abb0f93cSkardel * reference clock. This provides a mechanism in which the ordinary NTP 662abb0f93cSkardel * filter, selection and combining algorithms can be used to suppress 663abb0f93cSkardel * misbehaving radios and to mitigate between them when more than one is 664abb0f93cSkardel * available for backup. 665abb0f93cSkardel */ 666abb0f93cSkardel void 667abb0f93cSkardel refclock_receive( 668abb0f93cSkardel struct peer *peer /* peer structure pointer */ 669abb0f93cSkardel ) 670abb0f93cSkardel { 671abb0f93cSkardel struct refclockproc *pp; 672abb0f93cSkardel 673abb0f93cSkardel #ifdef DEBUG 674abb0f93cSkardel if (debug) 675abb0f93cSkardel printf("refclock_receive: at %lu %s\n", 676abb0f93cSkardel current_time, stoa(&peer->srcadr)); 677abb0f93cSkardel #endif 678abb0f93cSkardel 679abb0f93cSkardel /* 680abb0f93cSkardel * Do a little sanity dance and update the peer structure. Groom 681abb0f93cSkardel * the median filter samples and give the data to the clock 682abb0f93cSkardel * filter. 683abb0f93cSkardel */ 684abb0f93cSkardel pp = peer->procptr; 685cdfa2a7eSchristos pp->inpoll = FALSE; 686abb0f93cSkardel peer->leap = pp->leap; 687abb0f93cSkardel if (peer->leap == LEAP_NOTINSYNC) 688abb0f93cSkardel return; 689abb0f93cSkardel 690abb0f93cSkardel peer->received++; 691abb0f93cSkardel peer->timereceived = current_time; 692abb0f93cSkardel if (!peer->reach) { 693abb0f93cSkardel report_event(PEVNT_REACH, peer, NULL); 694abb0f93cSkardel peer->timereachable = current_time; 695abb0f93cSkardel } 696cdfa2a7eSchristos peer->reach = (peer->reach << (peer->reach & 1)) | 1; 697abb0f93cSkardel peer->reftime = pp->lastref; 698abb0f93cSkardel peer->aorg = pp->lastrec; 699abb0f93cSkardel peer->rootdisp = pp->disp; 700abb0f93cSkardel get_systime(&peer->dst); 701abb0f93cSkardel if (!refclock_sample(pp)) 702abb0f93cSkardel return; 703abb0f93cSkardel 704abb0f93cSkardel clock_filter(peer, pp->offset, 0., pp->jitter); 705abb0f93cSkardel if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != 706abb0f93cSkardel NULL) { 707abb0f93cSkardel if (sys_peer->refclktype == REFCLK_ATOM_PPS && 708abb0f93cSkardel peer->refclktype != REFCLK_ATOM_PPS) 709abb0f93cSkardel pp->fudgetime1 -= pp->offset * FUDGEFAC; 710abb0f93cSkardel } 711abb0f93cSkardel } 712abb0f93cSkardel 713abb0f93cSkardel 714abb0f93cSkardel /* 715abb0f93cSkardel * refclock_gtlin - groom next input line and extract timestamp 716abb0f93cSkardel * 717abb0f93cSkardel * This routine processes the timecode received from the clock and 718abb0f93cSkardel * strips the parity bit and control characters. It returns the number 719abb0f93cSkardel * of characters in the line followed by a NULL character ('\0'), which 720abb0f93cSkardel * is not included in the count. In case of an empty line, the previous 721abb0f93cSkardel * line is preserved. 722abb0f93cSkardel */ 723abb0f93cSkardel int 724abb0f93cSkardel refclock_gtlin( 725abb0f93cSkardel struct recvbuf *rbufp, /* receive buffer pointer */ 726abb0f93cSkardel char *lineptr, /* current line pointer */ 727abb0f93cSkardel int bmax, /* remaining characters in line */ 728abb0f93cSkardel l_fp *tsptr /* pointer to timestamp returned */ 729abb0f93cSkardel ) 730abb0f93cSkardel { 7312950cc38Schristos const char *sp, *spend; 7322950cc38Schristos char *dp, *dpend; 7332950cc38Schristos int dlen; 734abb0f93cSkardel 7352950cc38Schristos if (bmax <= 0) 7362950cc38Schristos return (0); 7372950cc38Schristos 7382950cc38Schristos dp = lineptr; 7392950cc38Schristos dpend = dp + bmax - 1; /* leave room for NUL pad */ 7402950cc38Schristos sp = (const char *)rbufp->recv_buffer; 7412950cc38Schristos spend = sp + rbufp->recv_length; 7422950cc38Schristos 7432950cc38Schristos while (sp != spend && dp != dpend) { 744abb0f93cSkardel char c; 745abb0f93cSkardel 7462950cc38Schristos c = *sp++ & 0x7f; 747abb0f93cSkardel if (c >= 0x20 && c < 0x7f) 748abb0f93cSkardel *dp++ = c; 749abb0f93cSkardel } 7502950cc38Schristos /* Get length of data written to the destination buffer. If 7512950cc38Schristos * zero, do *not* place a NUL byte to preserve the previous 7522950cc38Schristos * buffer content. 7532950cc38Schristos */ 7542950cc38Schristos dlen = dp - lineptr; 7552950cc38Schristos if (dlen) 756abb0f93cSkardel *dp = '\0'; 7572950cc38Schristos *tsptr = rbufp->recv_time; 7582950cc38Schristos DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n", 7592950cc38Schristos rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen, 7602950cc38Schristos (dlen != 0) 7612950cc38Schristos ? lineptr 7622950cc38Schristos : "")); 7632950cc38Schristos return (dlen); 764abb0f93cSkardel } 765abb0f93cSkardel 766abb0f93cSkardel 767abb0f93cSkardel /* 768abb0f93cSkardel * refclock_gtraw - get next line/chunk of data 769abb0f93cSkardel * 770abb0f93cSkardel * This routine returns the raw data received from the clock in both 771abb0f93cSkardel * canonical or raw modes. The terminal interface routines map CR to LF. 772abb0f93cSkardel * In canonical mode this results in two lines, one containing data 773abb0f93cSkardel * followed by LF and another containing only LF. In raw mode the 774abb0f93cSkardel * interface routines can deliver arbitraty chunks of data from one 775abb0f93cSkardel * character to a maximum specified by the calling routine. In either 776abb0f93cSkardel * mode the routine returns the number of characters in the line 777abb0f93cSkardel * followed by a NULL character ('\0'), which is not included in the 778abb0f93cSkardel * count. 779abb0f93cSkardel * 7802950cc38Schristos * *tsptr receives a copy of the buffer timestamp. 781abb0f93cSkardel */ 782abb0f93cSkardel int 783abb0f93cSkardel refclock_gtraw( 784abb0f93cSkardel struct recvbuf *rbufp, /* receive buffer pointer */ 785abb0f93cSkardel char *lineptr, /* current line pointer */ 786abb0f93cSkardel int bmax, /* remaining characters in line */ 787abb0f93cSkardel l_fp *tsptr /* pointer to timestamp returned */ 788abb0f93cSkardel ) 789abb0f93cSkardel { 7902950cc38Schristos if (bmax <= 0) 7912950cc38Schristos return (0); 7922950cc38Schristos bmax -= 1; /* leave room for trailing NUL */ 7932950cc38Schristos if (bmax > rbufp->recv_length) 7942950cc38Schristos bmax = rbufp->recv_length; 7952950cc38Schristos memcpy(lineptr, rbufp->recv_buffer, bmax); 7962950cc38Schristos lineptr[bmax] = '\0'; 797abb0f93cSkardel 7982950cc38Schristos *tsptr = rbufp->recv_time; 7992950cc38Schristos DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n", 8002950cc38Schristos rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax, 8012950cc38Schristos lineptr)); 8022950cc38Schristos return (bmax); 803abb0f93cSkardel } 804abb0f93cSkardel 805*eabc0478Schristos /* 806*eabc0478Schristos * refclock_fdwrite() 807*eabc0478Schristos * 808*eabc0478Schristos * Write data to a clock device. Does the necessary result checks and 809*eabc0478Schristos * logging, and encapsulates OS dependencies. 810*eabc0478Schristos */ 811*eabc0478Schristos #ifdef SYS_WINNT 812*eabc0478Schristos extern int async_write(int fd, const void * buf, unsigned int len); 813*eabc0478Schristos #endif 814*eabc0478Schristos 815*eabc0478Schristos size_t 816*eabc0478Schristos refclock_fdwrite( 817*eabc0478Schristos const struct peer * peer, 818*eabc0478Schristos int fd, 819*eabc0478Schristos const void * buf, 820*eabc0478Schristos size_t len, 821*eabc0478Schristos const char * what 822*eabc0478Schristos ) 823*eabc0478Schristos { 824*eabc0478Schristos size_t nret, nout; 825*eabc0478Schristos int nerr; 826*eabc0478Schristos 827*eabc0478Schristos nout = (INT_MAX > len) ? len : INT_MAX; 828*eabc0478Schristos # ifdef SYS_WINNT 829*eabc0478Schristos nret = (size_t)async_write(fd, buf, (unsigned int)nout); 830*eabc0478Schristos # else 831*eabc0478Schristos nret = (size_t)write(fd, buf, nout); 832*eabc0478Schristos # endif 833*eabc0478Schristos if (NULL != what) { 834*eabc0478Schristos if (nret == FDWRITE_ERROR) { 835*eabc0478Schristos nerr = errno; 836*eabc0478Schristos msyslog(LOG_INFO, 837*eabc0478Schristos "%s: write %s failed, fd=%d, %m", 838*eabc0478Schristos refnumtoa(&peer->srcadr), what, 839*eabc0478Schristos fd); 840*eabc0478Schristos errno = nerr; 841*eabc0478Schristos } else if (nret != len) { 842*eabc0478Schristos nerr = errno; 843*eabc0478Schristos msyslog(LOG_NOTICE, 844*eabc0478Schristos "%s: %s shortened, fd=%d, wrote %u of %u bytes", 845*eabc0478Schristos refnumtoa(&peer->srcadr), what, 846*eabc0478Schristos fd, (u_int)nret, (u_int)len); 847*eabc0478Schristos errno = nerr; 848*eabc0478Schristos } 849*eabc0478Schristos } 850*eabc0478Schristos return nret; 851*eabc0478Schristos } 852*eabc0478Schristos 853*eabc0478Schristos size_t 854*eabc0478Schristos refclock_write( 855*eabc0478Schristos const struct peer * peer, 856*eabc0478Schristos const void * buf, 857*eabc0478Schristos size_t len, 858*eabc0478Schristos const char * what 859*eabc0478Schristos ) 860*eabc0478Schristos { 861*eabc0478Schristos if ( ! (peer && peer->procptr)) { 862*eabc0478Schristos if (NULL != what) 863*eabc0478Schristos msyslog(LOG_INFO, 864*eabc0478Schristos "%s: write %s failed, invalid clock peer", 865*eabc0478Schristos refnumtoa(&peer->srcadr), what); 866*eabc0478Schristos errno = EINVAL; 867*eabc0478Schristos return FDWRITE_ERROR; 868*eabc0478Schristos } 869*eabc0478Schristos return refclock_fdwrite(peer, peer->procptr->io.fd, 870*eabc0478Schristos buf, len, what); 871*eabc0478Schristos } 8722950cc38Schristos 873abb0f93cSkardel /* 8742950cc38Schristos * indicate_refclock_packet() 8752950cc38Schristos * 8762950cc38Schristos * Passes a fragment of refclock input read from the device to the 8772950cc38Schristos * driver direct input routine, which may consume it (batch it for 8782950cc38Schristos * queuing once a logical unit is assembled). If it is not so 8792950cc38Schristos * consumed, queue it for the driver's receive entrypoint. 8802950cc38Schristos * 8812950cc38Schristos * The return value is TRUE if the data has been consumed as a fragment 8822950cc38Schristos * and should not be counted as a received packet. 883abb0f93cSkardel */ 8842950cc38Schristos int 8852950cc38Schristos indicate_refclock_packet( 8862950cc38Schristos struct refclockio * rio, 8872950cc38Schristos struct recvbuf * rb 8882950cc38Schristos ) 8892950cc38Schristos { 8902950cc38Schristos /* Does this refclock use direct input routine? */ 8912950cc38Schristos if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) { 8922950cc38Schristos /* 8932950cc38Schristos * data was consumed - nothing to pass up 8942950cc38Schristos * into block input machine 8952950cc38Schristos */ 8962950cc38Schristos freerecvbuf(rb); 8972950cc38Schristos 8982950cc38Schristos return TRUE; 899abb0f93cSkardel } 9002950cc38Schristos add_full_recv_buffer(rb); 9012950cc38Schristos 9022950cc38Schristos return FALSE; 9032950cc38Schristos } 9042950cc38Schristos 9052950cc38Schristos 9062950cc38Schristos /* 9072950cc38Schristos * process_refclock_packet() 9082950cc38Schristos * 9092950cc38Schristos * Used for deferred processing of 'io_input' on systems where threading 9102950cc38Schristos * is used (notably Windows). This is acting as a trampoline to make the 9112950cc38Schristos * real calls to the refclock functions. 9122950cc38Schristos */ 9132950cc38Schristos #ifdef HAVE_IO_COMPLETION_PORT 9142950cc38Schristos void 9152950cc38Schristos process_refclock_packet( 9162950cc38Schristos struct recvbuf * rb 9172950cc38Schristos ) 9182950cc38Schristos { 9192950cc38Schristos struct refclockio * rio; 9202950cc38Schristos 9212950cc38Schristos /* get the refclockio structure from the receive buffer */ 9222950cc38Schristos rio = &rb->recv_peer->procptr->io; 9232950cc38Schristos 9242950cc38Schristos /* call 'clock_recv' if either there is no input function or the 9252950cc38Schristos * raw input function tells us to feed the packet to the 9262950cc38Schristos * receiver. 9272950cc38Schristos */ 9282950cc38Schristos if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) { 9292950cc38Schristos rio->recvcount++; 9302950cc38Schristos packets_received++; 9312950cc38Schristos handler_pkts++; 9322950cc38Schristos (*rio->clock_recv)(rb); 9332950cc38Schristos } 9342950cc38Schristos } 9352950cc38Schristos #endif /* HAVE_IO_COMPLETION_PORT */ 936abb0f93cSkardel 937abb0f93cSkardel 938abb0f93cSkardel /* 939abb0f93cSkardel * The following code does not apply to WINNT & VMS ... 940abb0f93cSkardel */ 9412950cc38Schristos #if !defined(SYS_VXWORKS) && !defined(SYS_WINNT) 942abb0f93cSkardel #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 943abb0f93cSkardel 944abb0f93cSkardel /* 945abb0f93cSkardel * refclock_open - open serial port for reference clock 946abb0f93cSkardel * 947abb0f93cSkardel * This routine opens a serial port for I/O and sets default options. It 9482950cc38Schristos * returns the file descriptor if successful, or logs an error and 9492950cc38Schristos * returns -1. 950abb0f93cSkardel */ 951abb0f93cSkardel int 952abb0f93cSkardel refclock_open( 953*eabc0478Schristos const sockaddr_u *srcadr, 9548b8da087Schristos const char *dev, /* device name pointer */ 955abb0f93cSkardel u_int speed, /* serial port speed (code) */ 956abb0f93cSkardel u_int lflags /* line discipline flags */ 957abb0f93cSkardel ) 958abb0f93cSkardel { 959*eabc0478Schristos const char *cdev; 960abb0f93cSkardel int fd; 961abb0f93cSkardel int omode; 9623123f114Skardel #ifdef O_NONBLOCK 9633123f114Skardel char trash[128]; /* litter bin for old input data */ 9643123f114Skardel #endif 965abb0f93cSkardel 966abb0f93cSkardel /* 967abb0f93cSkardel * Open serial port and set default options 968abb0f93cSkardel */ 969abb0f93cSkardel omode = O_RDWR; 970abb0f93cSkardel #ifdef O_NONBLOCK 971abb0f93cSkardel omode |= O_NONBLOCK; 972abb0f93cSkardel #endif 973abb0f93cSkardel #ifdef O_NOCTTY 974abb0f93cSkardel omode |= O_NOCTTY; 975abb0f93cSkardel #endif 976abb0f93cSkardel 977*eabc0478Schristos if (NULL != (cdev = clockdev_lookup(srcadr, 0))) 978*eabc0478Schristos dev = cdev; 979*eabc0478Schristos 980abb0f93cSkardel fd = open(dev, omode, 0777); 9812950cc38Schristos /* refclock_open() long returned 0 on failure, avoid it. */ 9822950cc38Schristos if (0 == fd) { 9832950cc38Schristos fd = dup(0); 9842950cc38Schristos SAVE_ERRNO( 9852950cc38Schristos close(0); 9862950cc38Schristos ) 987abb0f93cSkardel } 9882950cc38Schristos if (fd < 0) { 9892950cc38Schristos SAVE_ERRNO( 9902950cc38Schristos msyslog(LOG_ERR, "refclock_open %s: %m", dev); 9912950cc38Schristos ) 9922950cc38Schristos return -1; 9932950cc38Schristos } 994abb0f93cSkardel if (!refclock_setup(fd, speed, lflags)) { 995abb0f93cSkardel close(fd); 9962950cc38Schristos return -1; 997abb0f93cSkardel } 998abb0f93cSkardel if (!refclock_ioctl(fd, lflags)) { 999abb0f93cSkardel close(fd); 10002950cc38Schristos return -1; 1001abb0f93cSkardel } 1002*eabc0478Schristos msyslog(LOG_NOTICE, "%s serial %s open at %d bps", 1003*eabc0478Schristos refnumtoa(srcadr), dev, symBaud2numBaud(speed)); 1004*eabc0478Schristos 10053123f114Skardel #ifdef O_NONBLOCK 10063123f114Skardel /* 10073123f114Skardel * We want to make sure there is no pending trash in the input 10083123f114Skardel * buffer. Since we have non-blocking IO available, this is a 10093123f114Skardel * good moment to read and dump all available outdated stuff 10103123f114Skardel * that might have become toxic for the driver. 10113123f114Skardel */ 10123123f114Skardel while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR) 10133123f114Skardel /*NOP*/; 10143123f114Skardel #endif 10152950cc38Schristos return fd; 1016abb0f93cSkardel } 1017abb0f93cSkardel 10183123f114Skardel 1019abb0f93cSkardel /* 1020abb0f93cSkardel * refclock_setup - initialize terminal interface structure 1021abb0f93cSkardel */ 1022abb0f93cSkardel int 1023abb0f93cSkardel refclock_setup( 1024abb0f93cSkardel int fd, /* file descriptor */ 1025abb0f93cSkardel u_int speed, /* serial port speed (code) */ 1026abb0f93cSkardel u_int lflags /* line discipline flags */ 1027abb0f93cSkardel ) 1028abb0f93cSkardel { 1029abb0f93cSkardel int i; 1030abb0f93cSkardel TTY ttyb, *ttyp; 1031abb0f93cSkardel 1032abb0f93cSkardel /* 1033abb0f93cSkardel * By default, the serial line port is initialized in canonical 1034abb0f93cSkardel * (line-oriented) mode at specified line speed, 8 bits and no 1035abb0f93cSkardel * parity. LF ends the line and CR is mapped to LF. The break, 1036abb0f93cSkardel * erase and kill functions are disabled. There is a different 1037abb0f93cSkardel * section for each terminal interface, as selected at compile 1038abb0f93cSkardel * time. The flag bits can be used to set raw mode and echo. 1039abb0f93cSkardel */ 1040abb0f93cSkardel ttyp = &ttyb; 1041abb0f93cSkardel #ifdef HAVE_TERMIOS 1042abb0f93cSkardel 1043abb0f93cSkardel /* 1044abb0f93cSkardel * POSIX serial line parameters (termios interface) 1045abb0f93cSkardel */ 1046abb0f93cSkardel if (tcgetattr(fd, ttyp) < 0) { 10472950cc38Schristos SAVE_ERRNO( 1048abb0f93cSkardel msyslog(LOG_ERR, 10492950cc38Schristos "refclock_setup fd %d tcgetattr: %m", 10502950cc38Schristos fd); 10512950cc38Schristos ) 10522950cc38Schristos return FALSE; 1053abb0f93cSkardel } 1054abb0f93cSkardel 1055abb0f93cSkardel /* 1056abb0f93cSkardel * Set canonical mode and local connection; set specified speed, 1057abb0f93cSkardel * 8 bits and no parity; map CR to NL; ignore break. 1058abb0f93cSkardel */ 1059abb0f93cSkardel if (speed) { 1060abb0f93cSkardel u_int ltemp = 0; 1061abb0f93cSkardel 1062abb0f93cSkardel ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 1063abb0f93cSkardel ttyp->c_oflag = 0; 1064abb0f93cSkardel ttyp->c_cflag = CS8 | CLOCAL | CREAD; 1065abb0f93cSkardel if (lflags & LDISC_7O1) { 1066abb0f93cSkardel /* HP Z3801A needs 7-bit, odd parity */ 1067abb0f93cSkardel ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; 1068abb0f93cSkardel } 1069abb0f93cSkardel cfsetispeed(&ttyb, speed); 1070abb0f93cSkardel cfsetospeed(&ttyb, speed); 1071abb0f93cSkardel for (i = 0; i < NCCS; ++i) 1072abb0f93cSkardel ttyp->c_cc[i] = '\0'; 1073abb0f93cSkardel 1074abb0f93cSkardel #if defined(TIOCMGET) && !defined(SCO5_CLOCK) 1075abb0f93cSkardel 1076abb0f93cSkardel /* 1077abb0f93cSkardel * If we have modem control, check to see if modem leads 1078abb0f93cSkardel * are active; if so, set remote connection. This is 1079abb0f93cSkardel * necessary for the kernel pps mods to work. 1080abb0f93cSkardel */ 1081abb0f93cSkardel if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 1082abb0f93cSkardel msyslog(LOG_ERR, 1083abb0f93cSkardel "refclock_setup fd %d TIOCMGET: %m", fd); 1084abb0f93cSkardel #ifdef DEBUG 1085abb0f93cSkardel if (debug) 1086abb0f93cSkardel printf("refclock_setup fd %d modem status: 0x%x\n", 1087abb0f93cSkardel fd, ltemp); 1088abb0f93cSkardel #endif 1089abb0f93cSkardel if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) 1090abb0f93cSkardel ttyp->c_cflag &= ~CLOCAL; 1091abb0f93cSkardel #endif /* TIOCMGET */ 1092abb0f93cSkardel } 1093abb0f93cSkardel 1094abb0f93cSkardel /* 1095abb0f93cSkardel * Set raw and echo modes. These can be changed on-fly. 1096abb0f93cSkardel */ 1097abb0f93cSkardel ttyp->c_lflag = ICANON; 1098abb0f93cSkardel if (lflags & LDISC_RAW) { 1099abb0f93cSkardel ttyp->c_lflag = 0; 1100abb0f93cSkardel ttyp->c_iflag = 0; 1101abb0f93cSkardel ttyp->c_cc[VMIN] = 1; 1102abb0f93cSkardel } 1103abb0f93cSkardel if (lflags & LDISC_ECHO) 1104abb0f93cSkardel ttyp->c_lflag |= ECHO; 1105abb0f93cSkardel if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 11062950cc38Schristos SAVE_ERRNO( 1107abb0f93cSkardel msyslog(LOG_ERR, 11082950cc38Schristos "refclock_setup fd %d TCSANOW: %m", 11092950cc38Schristos fd); 11102950cc38Schristos ) 11112950cc38Schristos return FALSE; 1112abb0f93cSkardel } 11133123f114Skardel 11143123f114Skardel /* 11153123f114Skardel * flush input and output buffers to discard any outdated stuff 11163123f114Skardel * that might have become toxic for the driver. Failing to do so 11173123f114Skardel * is logged, but we keep our fingers crossed otherwise. 11183123f114Skardel */ 11193123f114Skardel if (tcflush(fd, TCIOFLUSH) < 0) 11202950cc38Schristos msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", 11212950cc38Schristos fd); 1122abb0f93cSkardel #endif /* HAVE_TERMIOS */ 1123abb0f93cSkardel 1124abb0f93cSkardel #ifdef HAVE_SYSV_TTYS 1125abb0f93cSkardel 1126abb0f93cSkardel /* 1127abb0f93cSkardel * System V serial line parameters (termio interface) 1128abb0f93cSkardel * 1129abb0f93cSkardel */ 1130abb0f93cSkardel if (ioctl(fd, TCGETA, ttyp) < 0) { 11312950cc38Schristos SAVE_ERRNO( 1132abb0f93cSkardel msyslog(LOG_ERR, 11332950cc38Schristos "refclock_setup fd %d TCGETA: %m", 11342950cc38Schristos fd); 11352950cc38Schristos ) 11362950cc38Schristos return FALSE; 1137abb0f93cSkardel } 1138abb0f93cSkardel 1139abb0f93cSkardel /* 1140abb0f93cSkardel * Set canonical mode and local connection; set specified speed, 1141abb0f93cSkardel * 8 bits and no parity; map CR to NL; ignore break. 1142abb0f93cSkardel */ 1143abb0f93cSkardel if (speed) { 1144abb0f93cSkardel u_int ltemp = 0; 1145abb0f93cSkardel 1146abb0f93cSkardel ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 1147abb0f93cSkardel ttyp->c_oflag = 0; 1148abb0f93cSkardel ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 1149abb0f93cSkardel for (i = 0; i < NCCS; ++i) 1150abb0f93cSkardel ttyp->c_cc[i] = '\0'; 1151abb0f93cSkardel 1152abb0f93cSkardel #if defined(TIOCMGET) && !defined(SCO5_CLOCK) 1153abb0f93cSkardel 1154abb0f93cSkardel /* 1155abb0f93cSkardel * If we have modem control, check to see if modem leads 1156abb0f93cSkardel * are active; if so, set remote connection. This is 1157abb0f93cSkardel * necessary for the kernel pps mods to work. 1158abb0f93cSkardel */ 1159abb0f93cSkardel if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 1160abb0f93cSkardel msyslog(LOG_ERR, 1161abb0f93cSkardel "refclock_setup fd %d TIOCMGET: %m", fd); 1162abb0f93cSkardel #ifdef DEBUG 1163abb0f93cSkardel if (debug) 1164abb0f93cSkardel printf("refclock_setup fd %d modem status: %x\n", 1165abb0f93cSkardel fd, ltemp); 1166abb0f93cSkardel #endif 1167abb0f93cSkardel if (ltemp & TIOCM_DSR) 1168abb0f93cSkardel ttyp->c_cflag &= ~CLOCAL; 1169abb0f93cSkardel #endif /* TIOCMGET */ 1170abb0f93cSkardel } 1171abb0f93cSkardel 1172abb0f93cSkardel /* 1173abb0f93cSkardel * Set raw and echo modes. These can be changed on-fly. 1174abb0f93cSkardel */ 1175abb0f93cSkardel ttyp->c_lflag = ICANON; 1176abb0f93cSkardel if (lflags & LDISC_RAW) { 1177abb0f93cSkardel ttyp->c_lflag = 0; 1178abb0f93cSkardel ttyp->c_iflag = 0; 1179abb0f93cSkardel ttyp->c_cc[VMIN] = 1; 1180abb0f93cSkardel } 1181abb0f93cSkardel if (ioctl(fd, TCSETA, ttyp) < 0) { 11822950cc38Schristos SAVE_ERRNO( 1183abb0f93cSkardel msyslog(LOG_ERR, 1184abb0f93cSkardel "refclock_setup fd %d TCSETA: %m", fd); 11852950cc38Schristos ) 11862950cc38Schristos return FALSE; 1187abb0f93cSkardel } 1188abb0f93cSkardel #endif /* HAVE_SYSV_TTYS */ 1189abb0f93cSkardel 1190abb0f93cSkardel #ifdef HAVE_BSD_TTYS 1191abb0f93cSkardel 1192abb0f93cSkardel /* 1193abb0f93cSkardel * 4.3bsd serial line parameters (sgttyb interface) 1194abb0f93cSkardel */ 1195abb0f93cSkardel if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { 11962950cc38Schristos SAVE_ERRNO( 1197abb0f93cSkardel msyslog(LOG_ERR, 11982950cc38Schristos "refclock_setup fd %d TIOCGETP: %m", 11992950cc38Schristos fd); 12002950cc38Schristos ) 12012950cc38Schristos return FALSE; 1202abb0f93cSkardel } 1203abb0f93cSkardel if (speed) 1204abb0f93cSkardel ttyp->sg_ispeed = ttyp->sg_ospeed = speed; 1205abb0f93cSkardel ttyp->sg_flags = EVENP | ODDP | CRMOD; 1206abb0f93cSkardel if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { 12072950cc38Schristos SAVE_ERRNO( 12082950cc38Schristos msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); 12092950cc38Schristos ) 12102950cc38Schristos return FALSE; 1211abb0f93cSkardel } 1212abb0f93cSkardel #endif /* HAVE_BSD_TTYS */ 1213abb0f93cSkardel return(1); 1214abb0f93cSkardel } 1215abb0f93cSkardel #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 1216abb0f93cSkardel 1217abb0f93cSkardel 1218abb0f93cSkardel /* 1219abb0f93cSkardel * refclock_ioctl - set serial port control functions 1220abb0f93cSkardel * 1221abb0f93cSkardel * This routine attempts to hide the internal, system-specific details 1222abb0f93cSkardel * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 1223abb0f93cSkardel * (sgtty) interfaces with varying degrees of success. The routine sets 12242950cc38Schristos * up optional features such as tty_clk. The routine returns TRUE if 12252950cc38Schristos * successful. 1226abb0f93cSkardel */ 1227abb0f93cSkardel int 1228abb0f93cSkardel refclock_ioctl( 1229abb0f93cSkardel int fd, /* file descriptor */ 1230abb0f93cSkardel u_int lflags /* line discipline flags */ 1231abb0f93cSkardel ) 1232abb0f93cSkardel { 1233abb0f93cSkardel /* 12342950cc38Schristos * simply return TRUE if no UNIX line discipline is supported 1235abb0f93cSkardel */ 12362950cc38Schristos DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags)); 1237abb0f93cSkardel 12382950cc38Schristos return TRUE; 1239abb0f93cSkardel } 12402950cc38Schristos #endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */ 1241abb0f93cSkardel 1242abb0f93cSkardel 1243abb0f93cSkardel /* 1244abb0f93cSkardel * refclock_control - set and/or return clock values 1245abb0f93cSkardel * 1246abb0f93cSkardel * This routine is used mainly for debugging. It returns designated 1247abb0f93cSkardel * values from the interface structure that can be displayed using 1248abb0f93cSkardel * ntpdc and the clockstat command. It can also be used to initialize 1249abb0f93cSkardel * configuration variables, such as fudgetimes, fudgevalues, reference 1250abb0f93cSkardel * ID and stratum. 1251abb0f93cSkardel */ 1252abb0f93cSkardel void 1253abb0f93cSkardel refclock_control( 1254abb0f93cSkardel sockaddr_u *srcadr, 12552950cc38Schristos const struct refclockstat *in, 1256abb0f93cSkardel struct refclockstat *out 1257abb0f93cSkardel ) 1258abb0f93cSkardel { 1259abb0f93cSkardel struct peer *peer; 1260abb0f93cSkardel struct refclockproc *pp; 1261abb0f93cSkardel u_char clktype; 1262abb0f93cSkardel int unit; 1263abb0f93cSkardel 1264abb0f93cSkardel /* 1265abb0f93cSkardel * Check for valid address and running peer 1266abb0f93cSkardel */ 1267abb0f93cSkardel if (!ISREFCLOCKADR(srcadr)) 1268abb0f93cSkardel return; 1269abb0f93cSkardel 1270abb0f93cSkardel clktype = (u_char)REFCLOCKTYPE(srcadr); 1271abb0f93cSkardel unit = REFCLOCKUNIT(srcadr); 1272abb0f93cSkardel 12734eea345dSchristos peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); 1274abb0f93cSkardel 12752950cc38Schristos if (NULL == peer) 1276abb0f93cSkardel return; 1277abb0f93cSkardel 1278af12ab5eSchristos INSIST(peer->procptr != NULL); 1279abb0f93cSkardel pp = peer->procptr; 1280abb0f93cSkardel 1281abb0f93cSkardel /* 1282abb0f93cSkardel * Initialize requested data 1283abb0f93cSkardel */ 12842950cc38Schristos if (in != NULL) { 1285abb0f93cSkardel if (in->haveflags & CLK_HAVETIME1) 1286abb0f93cSkardel pp->fudgetime1 = in->fudgetime1; 1287abb0f93cSkardel if (in->haveflags & CLK_HAVETIME2) 1288abb0f93cSkardel pp->fudgetime2 = in->fudgetime2; 1289abb0f93cSkardel if (in->haveflags & CLK_HAVEVAL1) 1290abb0f93cSkardel peer->stratum = pp->stratum = (u_char)in->fudgeval1; 1291abb0f93cSkardel if (in->haveflags & CLK_HAVEVAL2) 1292abb0f93cSkardel peer->refid = pp->refid = in->fudgeval2; 1293abb0f93cSkardel if (in->haveflags & CLK_HAVEFLAG1) { 1294abb0f93cSkardel pp->sloppyclockflag &= ~CLK_FLAG1; 1295abb0f93cSkardel pp->sloppyclockflag |= in->flags & CLK_FLAG1; 1296abb0f93cSkardel } 1297abb0f93cSkardel if (in->haveflags & CLK_HAVEFLAG2) { 1298abb0f93cSkardel pp->sloppyclockflag &= ~CLK_FLAG2; 1299abb0f93cSkardel pp->sloppyclockflag |= in->flags & CLK_FLAG2; 1300abb0f93cSkardel } 1301abb0f93cSkardel if (in->haveflags & CLK_HAVEFLAG3) { 1302abb0f93cSkardel pp->sloppyclockflag &= ~CLK_FLAG3; 1303abb0f93cSkardel pp->sloppyclockflag |= in->flags & CLK_FLAG3; 1304abb0f93cSkardel } 1305abb0f93cSkardel if (in->haveflags & CLK_HAVEFLAG4) { 1306abb0f93cSkardel pp->sloppyclockflag &= ~CLK_FLAG4; 1307abb0f93cSkardel pp->sloppyclockflag |= in->flags & CLK_FLAG4; 1308abb0f93cSkardel } 1309cdfa2a7eSchristos if (in->haveflags & CLK_HAVEMINJIT) 1310cdfa2a7eSchristos pp->fudgeminjitter = in->fudgeminjitter; 1311abb0f93cSkardel } 1312abb0f93cSkardel 1313abb0f93cSkardel /* 1314abb0f93cSkardel * Readback requested data 1315abb0f93cSkardel */ 13162950cc38Schristos if (out != NULL) { 1317abb0f93cSkardel out->fudgeval1 = pp->stratum; 1318abb0f93cSkardel out->fudgeval2 = pp->refid; 13192950cc38Schristos out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; 13202950cc38Schristos out->fudgetime1 = pp->fudgetime1; 13212950cc38Schristos if (0.0 != out->fudgetime1) 13222950cc38Schristos out->haveflags |= CLK_HAVETIME1; 13232950cc38Schristos out->fudgetime2 = pp->fudgetime2; 13242950cc38Schristos if (0.0 != out->fudgetime2) 13252950cc38Schristos out->haveflags |= CLK_HAVETIME2; 1326abb0f93cSkardel out->flags = (u_char) pp->sloppyclockflag; 13272950cc38Schristos if (CLK_FLAG1 & out->flags) 13282950cc38Schristos out->haveflags |= CLK_HAVEFLAG1; 13292950cc38Schristos if (CLK_FLAG2 & out->flags) 13302950cc38Schristos out->haveflags |= CLK_HAVEFLAG2; 13312950cc38Schristos if (CLK_FLAG3 & out->flags) 13322950cc38Schristos out->haveflags |= CLK_HAVEFLAG3; 13332950cc38Schristos if (CLK_FLAG4 & out->flags) 13342950cc38Schristos out->haveflags |= CLK_HAVEFLAG4; 1335cdfa2a7eSchristos out->fudgeminjitter = pp->fudgeminjitter; 1336cdfa2a7eSchristos if (0.0 != out->fudgeminjitter) 1337cdfa2a7eSchristos out->haveflags |= CLK_HAVEMINJIT; 1338abb0f93cSkardel 1339abb0f93cSkardel out->timereset = current_time - pp->timestarted; 1340abb0f93cSkardel out->polls = pp->polls; 1341abb0f93cSkardel out->noresponse = pp->noreply; 1342abb0f93cSkardel out->badformat = pp->badformat; 1343abb0f93cSkardel out->baddata = pp->baddata; 1344abb0f93cSkardel 1345abb0f93cSkardel out->lastevent = pp->lastevent; 1346abb0f93cSkardel out->currentstatus = pp->currentstatus; 1347abb0f93cSkardel out->type = pp->type; 1348abb0f93cSkardel out->clockdesc = pp->clockdesc; 1349abb0f93cSkardel out->lencode = (u_short)pp->lencode; 1350abb0f93cSkardel out->p_lastcode = pp->a_lastcode; 1351abb0f93cSkardel } 1352abb0f93cSkardel 1353abb0f93cSkardel /* 1354abb0f93cSkardel * Give the stuff to the clock 1355abb0f93cSkardel */ 1356abb0f93cSkardel if (refclock_conf[clktype]->clock_control != noentry) 1357abb0f93cSkardel (refclock_conf[clktype]->clock_control)(unit, in, out, peer); 1358abb0f93cSkardel } 1359abb0f93cSkardel 1360abb0f93cSkardel 1361abb0f93cSkardel /* 1362abb0f93cSkardel * refclock_buginfo - return debugging info 1363abb0f93cSkardel * 1364abb0f93cSkardel * This routine is used mainly for debugging. It returns designated 1365abb0f93cSkardel * values from the interface structure that can be displayed using 1366abb0f93cSkardel * ntpdc and the clkbug command. 1367abb0f93cSkardel */ 1368abb0f93cSkardel void 1369abb0f93cSkardel refclock_buginfo( 1370abb0f93cSkardel sockaddr_u *srcadr, /* clock address */ 1371abb0f93cSkardel struct refclockbug *bug /* output structure */ 1372abb0f93cSkardel ) 1373abb0f93cSkardel { 1374abb0f93cSkardel struct peer *peer; 1375abb0f93cSkardel struct refclockproc *pp; 1376abb0f93cSkardel int clktype; 1377abb0f93cSkardel int unit; 1378abb0f93cSkardel unsigned u; 1379abb0f93cSkardel 1380abb0f93cSkardel /* 1381abb0f93cSkardel * Check for valid address and peer structure 1382abb0f93cSkardel */ 1383abb0f93cSkardel if (!ISREFCLOCKADR(srcadr)) 1384abb0f93cSkardel return; 1385abb0f93cSkardel 1386abb0f93cSkardel clktype = (u_char) REFCLOCKTYPE(srcadr); 1387abb0f93cSkardel unit = REFCLOCKUNIT(srcadr); 1388abb0f93cSkardel 13894eea345dSchristos peer = findexistingpeer(srcadr, NULL, NULL, -1, 0, NULL); 1390abb0f93cSkardel 1391abb0f93cSkardel if (NULL == peer || NULL == peer->procptr) 1392abb0f93cSkardel return; 1393abb0f93cSkardel 1394abb0f93cSkardel pp = peer->procptr; 1395abb0f93cSkardel 1396abb0f93cSkardel /* 1397abb0f93cSkardel * Copy structure values 1398abb0f93cSkardel */ 1399abb0f93cSkardel bug->nvalues = 8; 1400abb0f93cSkardel bug->svalues = 0x0000003f; 1401abb0f93cSkardel bug->values[0] = pp->year; 1402abb0f93cSkardel bug->values[1] = pp->day; 1403abb0f93cSkardel bug->values[2] = pp->hour; 1404abb0f93cSkardel bug->values[3] = pp->minute; 1405abb0f93cSkardel bug->values[4] = pp->second; 1406abb0f93cSkardel bug->values[5] = pp->nsec; 1407abb0f93cSkardel bug->values[6] = pp->yearstart; 1408abb0f93cSkardel bug->values[7] = pp->coderecv; 1409abb0f93cSkardel bug->stimes = 0xfffffffc; 1410abb0f93cSkardel bug->times[0] = pp->lastref; 1411abb0f93cSkardel bug->times[1] = pp->lastrec; 1412abb0f93cSkardel for (u = 2; u < bug->ntimes; u++) 1413abb0f93cSkardel DTOLFP(pp->filter[u - 2], &bug->times[u]); 1414abb0f93cSkardel 1415abb0f93cSkardel /* 1416abb0f93cSkardel * Give the stuff to the clock 1417abb0f93cSkardel */ 1418abb0f93cSkardel if (refclock_conf[clktype]->clock_buginfo != noentry) 1419abb0f93cSkardel (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 1420abb0f93cSkardel } 1421abb0f93cSkardel 1422abb0f93cSkardel 1423abb0f93cSkardel #ifdef HAVE_PPSAPI 1424abb0f93cSkardel /* 1425abb0f93cSkardel * refclock_ppsapi - initialize/update ppsapi 1426abb0f93cSkardel * 1427abb0f93cSkardel * This routine is called after the fudge command to open the PPSAPI 1428abb0f93cSkardel * interface for later parameter setting after the fudge command. 1429abb0f93cSkardel */ 1430abb0f93cSkardel int 1431abb0f93cSkardel refclock_ppsapi( 1432abb0f93cSkardel int fddev, /* fd device */ 1433abb0f93cSkardel struct refclock_atom *ap /* atom structure pointer */ 1434abb0f93cSkardel ) 1435abb0f93cSkardel { 1436abb0f93cSkardel if (ap->handle == 0) { 1437abb0f93cSkardel if (time_pps_create(fddev, &ap->handle) < 0) { 1438abb0f93cSkardel msyslog(LOG_ERR, 1439abb0f93cSkardel "refclock_ppsapi: time_pps_create: %m"); 1440abb0f93cSkardel return (0); 1441abb0f93cSkardel } 144203cfe0ffSchristos ZERO(ap->ts); /* [Bug 2689] defined INIT state */ 1443abb0f93cSkardel } 1444abb0f93cSkardel return (1); 1445abb0f93cSkardel } 1446abb0f93cSkardel 1447abb0f93cSkardel 1448abb0f93cSkardel /* 1449abb0f93cSkardel * refclock_params - set ppsapi parameters 1450abb0f93cSkardel * 1451abb0f93cSkardel * This routine is called to set the PPSAPI parameters after the fudge 1452abb0f93cSkardel * command. 1453abb0f93cSkardel */ 1454abb0f93cSkardel int 1455abb0f93cSkardel refclock_params( 1456abb0f93cSkardel int mode, /* mode bits */ 1457abb0f93cSkardel struct refclock_atom *ap /* atom structure pointer */ 1458abb0f93cSkardel ) 1459abb0f93cSkardel { 14602950cc38Schristos ZERO(ap->pps_params); 1461abb0f93cSkardel ap->pps_params.api_version = PPS_API_VERS_1; 1462abb0f93cSkardel 1463abb0f93cSkardel /* 1464abb0f93cSkardel * Solaris serial ports provide PPS pulse capture only on the 1465abb0f93cSkardel * assert edge. FreeBSD serial ports provide capture on the 1466abb0f93cSkardel * clear edge, while FreeBSD parallel ports provide capture 1467abb0f93cSkardel * on the assert edge. Your mileage may vary. 1468abb0f93cSkardel */ 1469abb0f93cSkardel if (mode & CLK_FLAG2) 1470abb0f93cSkardel ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; 1471abb0f93cSkardel else 1472abb0f93cSkardel ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; 1473abb0f93cSkardel if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { 1474abb0f93cSkardel msyslog(LOG_ERR, 1475abb0f93cSkardel "refclock_params: time_pps_setparams: %m"); 1476abb0f93cSkardel return (0); 1477abb0f93cSkardel } 1478abb0f93cSkardel 1479abb0f93cSkardel /* 1480ea66d795Schristos * If flag3 is lit, select the kernel PPS if we can. 14814eea345dSchristos * 14824eea345dSchristos * Note: EOPNOTSUPP is the only 'legal' error code we deal with; 14834eea345dSchristos * it is part of the 'if we can' strategy. Any other error 14844eea345dSchristos * indicates something more sinister and makes this function fail. 1485abb0f93cSkardel */ 1486abb0f93cSkardel if (mode & CLK_FLAG3) { 1487abb0f93cSkardel if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, 1488abb0f93cSkardel ap->pps_params.mode & ~PPS_TSFMT_TSPEC, 14894eea345dSchristos PPS_TSFMT_TSPEC) < 0) 14904eea345dSchristos { 14914eea345dSchristos if (errno != EOPNOTSUPP) { 1492abb0f93cSkardel msyslog(LOG_ERR, 1493abb0f93cSkardel "refclock_params: time_pps_kcbind: %m"); 1494abb0f93cSkardel return (0); 1495abb0f93cSkardel } 14964eea345dSchristos } else { 1497ea66d795Schristos hardpps_enable = 1; 1498abb0f93cSkardel } 14994eea345dSchristos } 1500abb0f93cSkardel return (1); 1501abb0f93cSkardel } 1502abb0f93cSkardel 1503abb0f93cSkardel 1504abb0f93cSkardel /* 1505abb0f93cSkardel * refclock_pps - called once per second 1506abb0f93cSkardel * 1507abb0f93cSkardel * This routine is called once per second. It snatches the PPS 1508abb0f93cSkardel * timestamp from the kernel and saves the sign-extended fraction in 1509abb0f93cSkardel * a circular buffer for processing at the next poll event. 1510abb0f93cSkardel */ 1511abb0f93cSkardel int 1512abb0f93cSkardel refclock_pps( 1513abb0f93cSkardel struct peer *peer, /* peer structure pointer */ 1514abb0f93cSkardel struct refclock_atom *ap, /* atom structure pointer */ 1515abb0f93cSkardel int mode /* mode bits */ 1516abb0f93cSkardel ) 1517abb0f93cSkardel { 1518abb0f93cSkardel struct refclockproc *pp; 1519abb0f93cSkardel pps_info_t pps_info; 1520abb0f93cSkardel struct timespec timeout; 152103cfe0ffSchristos double dtemp, dcorr, trash; 1522abb0f93cSkardel 1523abb0f93cSkardel /* 1524abb0f93cSkardel * We require the clock to be synchronized before setting the 1525abb0f93cSkardel * parameters. When the parameters have been set, fetch the 1526abb0f93cSkardel * most recent PPS timestamp. 1527abb0f93cSkardel */ 1528abb0f93cSkardel pp = peer->procptr; 1529abb0f93cSkardel if (ap->handle == 0) 1530abb0f93cSkardel return (0); 1531abb0f93cSkardel 1532abb0f93cSkardel if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { 1533abb0f93cSkardel if (refclock_params(pp->sloppyclockflag, ap) < 1) 1534abb0f93cSkardel return (0); 1535abb0f93cSkardel } 153603cfe0ffSchristos ZERO(timeout); 15372950cc38Schristos ZERO(pps_info); 1538abb0f93cSkardel if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, 1539abb0f93cSkardel &timeout) < 0) { 1540abb0f93cSkardel refclock_report(peer, CEVNT_FAULT); 1541abb0f93cSkardel return (0); 1542abb0f93cSkardel } 154303cfe0ffSchristos timeout = ap->ts; /* save old timestamp for check */ 1544abb0f93cSkardel if (ap->pps_params.mode & PPS_CAPTUREASSERT) 1545abb0f93cSkardel ap->ts = pps_info.assert_timestamp; 1546abb0f93cSkardel else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 1547abb0f93cSkardel ap->ts = pps_info.clear_timestamp; 1548abb0f93cSkardel else 1549abb0f93cSkardel return (0); 1550abb0f93cSkardel 155103cfe0ffSchristos /* [Bug 2689] Discard the first sample we read -- if the PPS 155203cfe0ffSchristos * source is currently down / disconnected, we have read a 155303cfe0ffSchristos * potentially *very* stale value here. So if our old TS value 155403cfe0ffSchristos * is all-zero, we consider this sample unrealiable and drop it. 155503cfe0ffSchristos * 155603cfe0ffSchristos * Note 1: a better check would compare the PPS time stamp to 155703cfe0ffSchristos * the current system time and drop it if it's more than say 3s 155803cfe0ffSchristos * away. 155903cfe0ffSchristos * 156003cfe0ffSchristos * Note 2: If we ever again get an all-zero PPS sample, the next 156103cfe0ffSchristos * one will be discarded. This can happen every 136yrs and is 156203cfe0ffSchristos * unlikely to be ever observed. 156303cfe0ffSchristos */ 156403cfe0ffSchristos if (0 == (timeout.tv_sec | timeout.tv_nsec)) 156503cfe0ffSchristos return (0); 156603cfe0ffSchristos 156703cfe0ffSchristos /* If the PPS source fails to deliver a new sample between 156803cfe0ffSchristos * polls, it regurgitates the last sample. We do not want to 156903cfe0ffSchristos * process the same sample multiple times. 157003cfe0ffSchristos */ 15712950cc38Schristos if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) 1572abb0f93cSkardel return (0); 1573abb0f93cSkardel 1574abb0f93cSkardel /* 157503cfe0ffSchristos * Convert to signed fraction offset, apply fudge and properly 157603cfe0ffSchristos * fold the correction into the [-0.5s,0.5s] range. Handle 157703cfe0ffSchristos * excessive fudge times, too. 157803cfe0ffSchristos */ 157903cfe0ffSchristos dtemp = ap->ts.tv_nsec / 1e9; 158003cfe0ffSchristos dcorr = modf((pp->fudgetime1 - dtemp), &trash); 158103cfe0ffSchristos if (dcorr > 0.5) 158203cfe0ffSchristos dcorr -= 1.0; 158303cfe0ffSchristos else if (dcorr < -0.5) 158403cfe0ffSchristos dcorr += 1.0; 158503cfe0ffSchristos 158603cfe0ffSchristos /* phase gate check: avoid wobbling by +/-1s when too close to 158703cfe0ffSchristos * the switch-over point. We allow +/-400ms max phase deviation. 158803cfe0ffSchristos * The trade-off is clear: The smaller the limit, the less 158903cfe0ffSchristos * sensitive to sampling noise the clock becomes. OTOH the 159003cfe0ffSchristos * system must get into phase gate range by other means for the 159103cfe0ffSchristos * PPS clock to lock in. 159203cfe0ffSchristos */ 159303cfe0ffSchristos if (fabs(dcorr) > 0.4) 159403cfe0ffSchristos return (0); 159503cfe0ffSchristos 159603cfe0ffSchristos /* 159703cfe0ffSchristos * record this time stamp and stuff in median filter 1598abb0f93cSkardel */ 15993123f114Skardel pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; 1600abb0f93cSkardel pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); 1601cdfa2a7eSchristos clk_add_sample(pp, dcorr); 1602cdfa2a7eSchristos refclock_checkburst(peer, pp); 160303cfe0ffSchristos 1604abb0f93cSkardel #ifdef DEBUG 1605abb0f93cSkardel if (debug > 1) 1606abb0f93cSkardel printf("refclock_pps: %lu %f %f\n", current_time, 160703cfe0ffSchristos dcorr, pp->fudgetime1); 1608abb0f93cSkardel #endif 1609abb0f93cSkardel return (1); 1610abb0f93cSkardel } 1611abb0f93cSkardel #endif /* HAVE_PPSAPI */ 1612cdfa2a7eSchristos 1613cdfa2a7eSchristos 1614cdfa2a7eSchristos /* 1615cdfa2a7eSchristos * ------------------------------------------------------------------- 1616cdfa2a7eSchristos * refclock_ppsaugment(...) -- correlate with PPS edge 1617cdfa2a7eSchristos * 1618cdfa2a7eSchristos * This function is used to correlate a receive time stamp with a PPS 1619cdfa2a7eSchristos * edge time stamp. It applies the necessary fudges and then tries to 1620cdfa2a7eSchristos * move the receive time stamp to the corresponding edge. This can warp 1621cdfa2a7eSchristos * into future, if a transmission delay of more than 500ms is not 1622cdfa2a7eSchristos * compensated with a corresponding fudge time2 value, because then the 1623cdfa2a7eSchristos * next PPS edge is nearer than the last. (Similiar to what the PPS ATOM 1624cdfa2a7eSchristos * driver does, but we deal with full time stamps here, not just phase 1625cdfa2a7eSchristos * shift information.) Likewise, a negative fudge time2 value must be 1626cdfa2a7eSchristos * used if the reference time stamp correlates with the *following* PPS 1627cdfa2a7eSchristos * pulse. 1628cdfa2a7eSchristos * 1629cdfa2a7eSchristos * Note that the receive time fudge value only needs to move the receive 1630cdfa2a7eSchristos * stamp near a PPS edge but that close proximity is not required; 1631cdfa2a7eSchristos * +/-100ms precision should be enough. But since the fudge value will 1632cdfa2a7eSchristos * probably also be used to compensate the transmission delay when no 1633cdfa2a7eSchristos * PPS edge can be related to the time stamp, it's best to get it as 1634cdfa2a7eSchristos * close as possible. 1635cdfa2a7eSchristos * 1636cdfa2a7eSchristos * It should also be noted that the typical use case is matching to the 1637cdfa2a7eSchristos * preceeding edge, as most units relate their sentences to the current 1638cdfa2a7eSchristos * second. 1639cdfa2a7eSchristos * 1640cdfa2a7eSchristos * The function returns FALSE if there is no correlation possible, TRUE 1641cdfa2a7eSchristos * otherwise. Reason for failures are: 1642cdfa2a7eSchristos * 1643cdfa2a7eSchristos * - no PPS/ATOM unit given 1644cdfa2a7eSchristos * - PPS stamp is stale (that is, the difference between the PPS stamp 1645cdfa2a7eSchristos * and the corrected time stamp would exceed two seconds) 1646cdfa2a7eSchristos * - The phase difference is too close to 0.5, and the decision wether 1647cdfa2a7eSchristos * to move up or down is too sensitive to noise. 1648cdfa2a7eSchristos * 1649cdfa2a7eSchristos * On output, the receive time stamp is updated with the 'fixed' receive 1650cdfa2a7eSchristos * time. 1651cdfa2a7eSchristos * ------------------------------------------------------------------- 1652cdfa2a7eSchristos */ 1653cdfa2a7eSchristos 1654*eabc0478Schristos int 1655cdfa2a7eSchristos refclock_ppsaugment( 1656cdfa2a7eSchristos const struct refclock_atom * ap , /* for PPS io */ 1657cdfa2a7eSchristos l_fp * rcvtime , 1658cdfa2a7eSchristos double rcvfudge, /* i/o read fudge */ 1659cdfa2a7eSchristos double ppsfudge /* pps fudge */ 1660cdfa2a7eSchristos ) 1661cdfa2a7eSchristos { 1662cdfa2a7eSchristos l_fp delta[1]; 1663cdfa2a7eSchristos 1664cdfa2a7eSchristos #ifdef HAVE_PPSAPI 1665cdfa2a7eSchristos 1666cdfa2a7eSchristos pps_info_t pps_info; 1667cdfa2a7eSchristos struct timespec timeout; 1668cdfa2a7eSchristos l_fp stamp[1]; 1669cdfa2a7eSchristos uint32_t phase; 1670cdfa2a7eSchristos 1671cdfa2a7eSchristos static const uint32_t s_plim_hi = UINT32_C(1932735284); 1672cdfa2a7eSchristos static const uint32_t s_plim_lo = UINT32_C(2362232013); 1673cdfa2a7eSchristos 1674cdfa2a7eSchristos /* fixup receive time in case we have to bail out early */ 1675cdfa2a7eSchristos DTOLFP(rcvfudge, delta); 1676cdfa2a7eSchristos L_SUB(rcvtime, delta); 1677cdfa2a7eSchristos 1678cdfa2a7eSchristos if (NULL == ap) 1679cdfa2a7eSchristos return FALSE; 1680cdfa2a7eSchristos 1681cdfa2a7eSchristos ZERO(timeout); 1682cdfa2a7eSchristos ZERO(pps_info); 1683cdfa2a7eSchristos 1684cdfa2a7eSchristos /* fetch PPS stamp from ATOM block */ 1685cdfa2a7eSchristos if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, 1686cdfa2a7eSchristos &pps_info, &timeout) < 0) 1687cdfa2a7eSchristos return FALSE; /* can't get time stamps */ 1688cdfa2a7eSchristos 1689cdfa2a7eSchristos /* get last active PPS edge before receive */ 1690cdfa2a7eSchristos if (ap->pps_params.mode & PPS_CAPTUREASSERT) 1691cdfa2a7eSchristos timeout = pps_info.assert_timestamp; 1692cdfa2a7eSchristos else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 1693cdfa2a7eSchristos timeout = pps_info.clear_timestamp; 1694cdfa2a7eSchristos else 1695cdfa2a7eSchristos return FALSE; /* WHICH edge, please?!? */ 1696cdfa2a7eSchristos 1697cdfa2a7eSchristos /* convert PPS stamp to l_fp and apply fudge */ 1698cdfa2a7eSchristos *stamp = tspec_stamp_to_lfp(timeout); 1699cdfa2a7eSchristos DTOLFP(ppsfudge, delta); 1700cdfa2a7eSchristos L_SUB(stamp, delta); 1701cdfa2a7eSchristos 1702cdfa2a7eSchristos /* Get difference between PPS stamp (--> yield) and receive time 1703cdfa2a7eSchristos * (--> base) 1704cdfa2a7eSchristos */ 1705cdfa2a7eSchristos *delta = *stamp; 1706cdfa2a7eSchristos L_SUB(delta, rcvtime); 1707cdfa2a7eSchristos 1708cdfa2a7eSchristos /* check if either the PPS or the STAMP is stale in relation 1709cdfa2a7eSchristos * to each other. Bail if it is so... 1710cdfa2a7eSchristos */ 1711cdfa2a7eSchristos phase = delta->l_ui; 1712cdfa2a7eSchristos if (phase >= 2 && phase < (uint32_t)-2) 1713cdfa2a7eSchristos return FALSE; /* PPS is stale, don't use it */ 1714cdfa2a7eSchristos 1715cdfa2a7eSchristos /* If the phase is too close to 0.5, the decision whether to 1716cdfa2a7eSchristos * move up or down is becoming noise sensitive. That is, we 1717cdfa2a7eSchristos * might amplify usec noise between samples into seconds with a 1718cdfa2a7eSchristos * simple threshold. This can be solved by a Schmitt Trigger 1719cdfa2a7eSchristos * characteristic, but that would also require additional state 1720cdfa2a7eSchristos * where we could remember previous decisions. Easier to play 1721cdfa2a7eSchristos * dead duck and wait for the conditions to become clear. 1722cdfa2a7eSchristos */ 1723cdfa2a7eSchristos phase = delta->l_uf; 1724cdfa2a7eSchristos if (phase > s_plim_hi && phase < s_plim_lo) 1725cdfa2a7eSchristos return FALSE; /* we're in the noise lock gap */ 1726cdfa2a7eSchristos 1727cdfa2a7eSchristos /* sign-extend fraction into seconds */ 1728cdfa2a7eSchristos delta->l_ui = UINT32_C(0) - ((phase >> 31) & 1); 1729cdfa2a7eSchristos /* add it up now */ 1730cdfa2a7eSchristos L_ADD(rcvtime, delta); 1731cdfa2a7eSchristos return TRUE; 1732cdfa2a7eSchristos 1733cdfa2a7eSchristos # else /* have no PPS support at all */ 1734cdfa2a7eSchristos 1735cdfa2a7eSchristos /* just fixup receive time and fail */ 1736cdfa2a7eSchristos UNUSED_ARG(ap); 1737cdfa2a7eSchristos UNUSED_ARG(ppsfudge); 1738cdfa2a7eSchristos 1739cdfa2a7eSchristos DTOLFP(rcvfudge, delta); 1740cdfa2a7eSchristos L_SUB(rcvtime, delta); 1741cdfa2a7eSchristos return FALSE; 1742cdfa2a7eSchristos 1743cdfa2a7eSchristos # endif 1744cdfa2a7eSchristos } 1745cdfa2a7eSchristos 1746cdfa2a7eSchristos /* 1747cdfa2a7eSchristos * ------------------------------------------------------------------- 1748cdfa2a7eSchristos * check if it makes sense to schedule an 'early' poll to get the clock 1749cdfa2a7eSchristos * up fast after start or longer signal dropout. 1750cdfa2a7eSchristos */ 1751cdfa2a7eSchristos static void 1752cdfa2a7eSchristos refclock_checkburst( 1753cdfa2a7eSchristos struct peer * peer, 1754cdfa2a7eSchristos struct refclockproc * pp 1755cdfa2a7eSchristos ) 1756cdfa2a7eSchristos { 1757cdfa2a7eSchristos uint32_t limit; /* when we should poll */ 1758cdfa2a7eSchristos u_int needs; /* needed number of samples */ 1759cdfa2a7eSchristos 1760cdfa2a7eSchristos /* Paranoia: stop here if peer and clockproc don't match up. 1761cdfa2a7eSchristos * And when a poll is actually pending, we don't have to do 1762cdfa2a7eSchristos * anything, either. Likewise if the reach mask is full, of 1763cdfa2a7eSchristos * course, and if the filter has stabilized. 1764cdfa2a7eSchristos */ 1765cdfa2a7eSchristos if (pp->inpoll || (peer->procptr != pp) || 1766cdfa2a7eSchristos ((peer->reach == 0xFF) && (peer->disp <= MAXDISTANCE))) 1767cdfa2a7eSchristos return; 1768cdfa2a7eSchristos 1769cdfa2a7eSchristos /* If the next poll is soon enough, bail out, too: */ 1770cdfa2a7eSchristos limit = current_time + 1; 1771cdfa2a7eSchristos if (peer->nextdate <= limit) 1772cdfa2a7eSchristos return; 1773cdfa2a7eSchristos 1774cdfa2a7eSchristos /* Derive the number of samples needed from the popcount of the 1775cdfa2a7eSchristos * reach mask. With less samples available, we break away. 1776cdfa2a7eSchristos */ 1777cdfa2a7eSchristos needs = peer->reach; 1778cdfa2a7eSchristos needs -= (needs >> 1) & 0x55; 1779cdfa2a7eSchristos needs = (needs & 0x33) + ((needs >> 2) & 0x33); 1780cdfa2a7eSchristos needs = (needs + (needs >> 4)) & 0x0F; 1781cdfa2a7eSchristos if (needs > 6) 1782cdfa2a7eSchristos needs = 6; 1783cdfa2a7eSchristos else if (needs < 3) 1784cdfa2a7eSchristos needs = 3; 1785cdfa2a7eSchristos if (clk_cnt_sample(pp) < needs) 1786cdfa2a7eSchristos return; 1787cdfa2a7eSchristos 1788cdfa2a7eSchristos /* Get serious. Reduce the poll to minimum and schedule early. 1789cdfa2a7eSchristos * (Changing the peer poll is probably in vain, as it will be 1790cdfa2a7eSchristos * re-adjusted, but maybe some time the hint will work...) 1791cdfa2a7eSchristos */ 1792cdfa2a7eSchristos peer->hpoll = peer->minpoll; 1793cdfa2a7eSchristos peer->nextdate = limit; 1794cdfa2a7eSchristos } 1795cdfa2a7eSchristos 1796cdfa2a7eSchristos /* 1797cdfa2a7eSchristos * ------------------------------------------------------------------- 1798cdfa2a7eSchristos * Save the last timecode string, making sure it's properly truncated 1799cdfa2a7eSchristos * if necessary and NUL terminated in any case. 1800cdfa2a7eSchristos */ 1801cdfa2a7eSchristos void 1802cdfa2a7eSchristos refclock_save_lcode( 1803cdfa2a7eSchristos struct refclockproc * pp, 1804cdfa2a7eSchristos char const * tc, 1805cdfa2a7eSchristos size_t len 1806cdfa2a7eSchristos ) 1807cdfa2a7eSchristos { 1808cdfa2a7eSchristos if (len == (size_t)-1) 1809cdfa2a7eSchristos len = strnlen(tc, sizeof(pp->a_lastcode) - 1); 1810cdfa2a7eSchristos else if (len >= sizeof(pp->a_lastcode)) 1811cdfa2a7eSchristos len = sizeof(pp->a_lastcode) - 1; 1812cdfa2a7eSchristos 1813cdfa2a7eSchristos pp->lencode = (u_short)len; 1814cdfa2a7eSchristos memcpy(pp->a_lastcode, tc, len); 1815cdfa2a7eSchristos pp->a_lastcode[len] = '\0'; 1816cdfa2a7eSchristos } 1817cdfa2a7eSchristos 1818cdfa2a7eSchristos /* format data into a_lastcode */ 1819cdfa2a7eSchristos void 1820cdfa2a7eSchristos refclock_vformat_lcode( 1821cdfa2a7eSchristos struct refclockproc * pp, 1822cdfa2a7eSchristos char const * fmt, 1823cdfa2a7eSchristos va_list va 1824cdfa2a7eSchristos ) 1825cdfa2a7eSchristos { 1826cdfa2a7eSchristos long len; 1827cdfa2a7eSchristos 1828cdfa2a7eSchristos len = vsnprintf(pp->a_lastcode, sizeof(pp->a_lastcode), fmt, va); 1829*eabc0478Schristos if (len <= 0) { 1830cdfa2a7eSchristos len = 0; 1831*eabc0478Schristos } else if ((size_t)len >= sizeof(pp->a_lastcode)) { 1832cdfa2a7eSchristos len = sizeof(pp->a_lastcode) - 1; 1833*eabc0478Schristos } 1834cdfa2a7eSchristos 1835cdfa2a7eSchristos pp->lencode = (u_short)len; 1836cdfa2a7eSchristos pp->a_lastcode[len] = '\0'; 1837cdfa2a7eSchristos /* !note! the NUL byte is needed in case vsnprintf() really fails */ 1838cdfa2a7eSchristos } 1839cdfa2a7eSchristos 1840cdfa2a7eSchristos void 1841cdfa2a7eSchristos refclock_format_lcode( 1842cdfa2a7eSchristos struct refclockproc * pp, 1843cdfa2a7eSchristos char const * fmt, 1844cdfa2a7eSchristos ... 1845cdfa2a7eSchristos ) 1846cdfa2a7eSchristos { 1847cdfa2a7eSchristos va_list va; 1848cdfa2a7eSchristos 1849cdfa2a7eSchristos va_start(va, fmt); 1850cdfa2a7eSchristos refclock_vformat_lcode(pp, fmt, va); 1851cdfa2a7eSchristos va_end(va); 1852cdfa2a7eSchristos } 1853cdfa2a7eSchristos 1854abb0f93cSkardel #endif /* REFCLOCK */ 1855