154359Sroberto/* 254359Sroberto * ntp_refclock - processing support for reference clocks 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include "ntpd.h" 954359Sroberto#include "ntp_io.h" 1054359Sroberto#include "ntp_unixtime.h" 1182498Sroberto#include "ntp_tty.h" 1254359Sroberto#include "ntp_refclock.h" 1354359Sroberto#include "ntp_stdlib.h" 14290000Sglebius#include "ntp_assert.h" 1554359Sroberto 1682498Sroberto#include <stdio.h> 1782498Sroberto 1882498Sroberto#ifdef HAVE_SYS_IOCTL_H 1982498Sroberto# include <sys/ioctl.h> 2082498Sroberto#endif /* HAVE_SYS_IOCTL_H */ 2182498Sroberto 2254359Sroberto#ifdef REFCLOCK 2354359Sroberto 2482498Sroberto#ifdef KERNEL_PLL 2582498Sroberto#include "ntp_syscall.h" 2682498Sroberto#endif /* KERNEL_PLL */ 2754359Sroberto 28290000Sglebius#ifdef HAVE_PPSAPI 29290000Sglebius#include "ppsapi_timepps.h" 30290000Sglebius#include "refclock_atom.h" 31290000Sglebius#endif /* HAVE_PPSAPI */ 32290000Sglebius 3354359Sroberto/* 3454359Sroberto * Reference clock support is provided here by maintaining the fiction 35290000Sglebius * that the clock is actually a peer. As no packets are exchanged with 36290000Sglebius * a reference clock, however, we replace the transmit, receive and 37290000Sglebius * packet procedures with separate code to simulate them. Routines 3854359Sroberto * refclock_transmit() and refclock_receive() maintain the peer 3954359Sroberto * variables in a state analogous to an actual peer and pass reference 40290000Sglebius * clock data on through the filters. Routines refclock_peer() and 4154359Sroberto * refclock_unpeer() are called to initialize and terminate reference 42290000Sglebius * clock associations. A set of utility routines is included to open 43290000Sglebius * serial devices, process sample data, and to perform various debugging 44290000Sglebius * functions. 4554359Sroberto * 4654359Sroberto * The main interface used by these routines is the refclockproc 47290000Sglebius * structure, which contains for most drivers the decimal equivalants 48290000Sglebius * of the year, day, month, hour, second and millisecond/microsecond 49290000Sglebius * decoded from the ASCII timecode. Additional information includes 50290000Sglebius * the receive timestamp, exception report, statistics tallies, etc. 51290000Sglebius * In addition, there may be a driver-specific unit structure used for 5254359Sroberto * local control of the device. 5354359Sroberto * 5454359Sroberto * The support routines are passed a pointer to the peer structure, 55290000Sglebius * which is used for all peer-specific processing and contains a 56290000Sglebius * pointer to the refclockproc structure, which in turn contains a 57290000Sglebius * pointer to the unit structure, if used. The peer structure is 58290000Sglebius * identified by an interface address in the dotted quad form 59290000Sglebius * 127.127.t.u, where t is the clock type and u the unit. 6054359Sroberto */ 6182498Sroberto#define FUDGEFAC .1 /* fudge correction factor */ 62182007Sroberto#define LF 0x0a /* ASCII LF */ 6354359Sroberto 64182007Srobertoint cal_enable; /* enable refclock calibrate */ 6554359Sroberto 6654359Sroberto/* 6754359Sroberto * Forward declarations 6854359Sroberto */ 69290000Sglebiusstatic int refclock_cmpl_fp (const void *, const void *); 70290000Sglebiusstatic int refclock_sample (struct refclockproc *); 71290000Sglebiusstatic int refclock_ioctl(int, u_int); 7254359Sroberto 73182007Sroberto 7454359Sroberto/* 7554359Sroberto * refclock_report - note the occurance of an event 7654359Sroberto * 7754359Sroberto * This routine presently just remembers the report and logs it, but 7854359Sroberto * does nothing heroic for the trap handler. It tries to be a good 7954359Sroberto * citizen and bothers the system log only if things change. 8054359Sroberto */ 8154359Srobertovoid 8254359Srobertorefclock_report( 8354359Sroberto struct peer *peer, 8454359Sroberto int code 8554359Sroberto ) 8654359Sroberto{ 8754359Sroberto struct refclockproc *pp; 8854359Sroberto 89132451Sroberto pp = peer->procptr; 90132451Sroberto if (pp == NULL) 9154359Sroberto return; 92182007Sroberto 93182007Sroberto switch (code) { 94182007Sroberto 95290000Sglebius case CEVNT_TIMEOUT: 96290000Sglebius pp->noreply++; 97290000Sglebius break; 98182007Sroberto 99290000Sglebius case CEVNT_BADREPLY: 100290000Sglebius pp->badformat++; 101290000Sglebius break; 102182007Sroberto 103290000Sglebius case CEVNT_FAULT: 104290000Sglebius break; 105182007Sroberto 106290000Sglebius case CEVNT_BADDATE: 107290000Sglebius case CEVNT_BADTIME: 108290000Sglebius pp->baddata++; 109290000Sglebius break; 110182007Sroberto 111290000Sglebius default: 112290000Sglebius /* ignore others */ 113290000Sglebius break; 114182007Sroberto } 115290000Sglebius if (pp->lastevent < 15) 116290000Sglebius pp->lastevent++; 11754359Sroberto if (pp->currentstatus != code) { 118132451Sroberto pp->currentstatus = (u_char)code; 119290000Sglebius report_event(PEVNT_CLOCK, peer, ceventstr(code)); 12054359Sroberto } 12154359Sroberto} 12254359Sroberto 123290000Sglebius 12454359Sroberto/* 12554359Sroberto * init_refclock - initialize the reference clock drivers 12654359Sroberto * 12754359Sroberto * This routine calls each of the drivers in turn to initialize internal 12854359Sroberto * variables, if necessary. Most drivers have nothing to say at this 12954359Sroberto * point. 13054359Sroberto */ 13154359Srobertovoid 13254359Srobertoinit_refclock(void) 13354359Sroberto{ 134290000Sglebius int i; 13554359Sroberto 136290000Sglebius for (i = 0; i < (int)num_refclock_conf; i++) 13754359Sroberto if (refclock_conf[i]->clock_init != noentry) 13854359Sroberto (refclock_conf[i]->clock_init)(); 13954359Sroberto} 14054359Sroberto 14154359Sroberto 14254359Sroberto/* 14354359Sroberto * refclock_newpeer - initialize and start a reference clock 14454359Sroberto * 14554359Sroberto * This routine allocates and initializes the interface structure which 14654359Sroberto * supports a reference clock in the form of an ordinary NTP peer. A 14754359Sroberto * driver-specific support routine completes the initialization, if 14854359Sroberto * used. Default peer variables which identify the clock and establish 14954359Sroberto * its reference ID and stratum are set here. It returns one if success 15054359Sroberto * and zero if the clock address is invalid or already running, 15154359Sroberto * insufficient resources are available or the driver declares a bum 15254359Sroberto * rap. 15354359Sroberto */ 15454359Srobertoint 15554359Srobertorefclock_newpeer( 15654359Sroberto struct peer *peer /* peer structure pointer */ 15754359Sroberto ) 15854359Sroberto{ 15954359Sroberto struct refclockproc *pp; 16054359Sroberto u_char clktype; 16154359Sroberto int unit; 16254359Sroberto 16354359Sroberto /* 16454359Sroberto * Check for valid clock address. If already running, shut it 16554359Sroberto * down first. 16654359Sroberto */ 16754359Sroberto if (!ISREFCLOCKADR(&peer->srcadr)) { 16854359Sroberto msyslog(LOG_ERR, 16954359Sroberto "refclock_newpeer: clock address %s invalid", 170132451Sroberto stoa(&peer->srcadr)); 17154359Sroberto return (0); 17254359Sroberto } 17354359Sroberto clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 17454359Sroberto unit = REFCLOCKUNIT(&peer->srcadr); 175290000Sglebius if (clktype >= num_refclock_conf || 17654359Sroberto refclock_conf[clktype]->clock_start == noentry) { 17754359Sroberto msyslog(LOG_ERR, 17854359Sroberto "refclock_newpeer: clock type %d invalid\n", 17954359Sroberto clktype); 18054359Sroberto return (0); 18154359Sroberto } 18254359Sroberto 18354359Sroberto /* 18454359Sroberto * Allocate and initialize interface structure 18554359Sroberto */ 186290000Sglebius pp = emalloc_zero(sizeof(*pp)); 18754359Sroberto peer->procptr = pp; 18854359Sroberto 18954359Sroberto /* 19054359Sroberto * Initialize structures 19154359Sroberto */ 19254359Sroberto peer->refclktype = clktype; 193132451Sroberto peer->refclkunit = (u_char)unit; 194290000Sglebius peer->flags |= FLAG_REFCLOCK; 195182007Sroberto peer->leap = LEAP_NOTINSYNC; 19654359Sroberto peer->stratum = STRATUM_REFCLOCK; 197182007Sroberto peer->ppoll = peer->maxpoll; 19854359Sroberto pp->type = clktype; 199290000Sglebius pp->conf = refclock_conf[clktype]; 20054359Sroberto pp->timestarted = current_time; 201290000Sglebius pp->io.fd = -1; 20254359Sroberto 20354359Sroberto /* 20454359Sroberto * Set peer.pmode based on the hmode. For appearances only. 20554359Sroberto */ 20654359Sroberto switch (peer->hmode) { 207132451Sroberto case MODE_ACTIVE: 20854359Sroberto peer->pmode = MODE_PASSIVE; 20954359Sroberto break; 21054359Sroberto 211132451Sroberto default: 21254359Sroberto peer->pmode = MODE_SERVER; 21354359Sroberto break; 21454359Sroberto } 21554359Sroberto 21654359Sroberto /* 21754359Sroberto * Do driver dependent initialization. The above defaults 21854359Sroberto * can be wiggled, then finish up for consistency. 21954359Sroberto */ 22054359Sroberto if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { 22182498Sroberto refclock_unpeer(peer); 22254359Sroberto return (0); 22354359Sroberto } 224132451Sroberto peer->refid = pp->refid; 22554359Sroberto return (1); 22654359Sroberto} 22754359Sroberto 22854359Sroberto 22954359Sroberto/* 23054359Sroberto * refclock_unpeer - shut down a clock 23154359Sroberto */ 23254359Srobertovoid 23354359Srobertorefclock_unpeer( 23454359Sroberto struct peer *peer /* peer structure pointer */ 23554359Sroberto ) 23654359Sroberto{ 23754359Sroberto u_char clktype; 23854359Sroberto int unit; 23954359Sroberto 24054359Sroberto /* 24154359Sroberto * Wiggle the driver to release its resources, then give back 24254359Sroberto * the interface structure. 24354359Sroberto */ 244290000Sglebius if (NULL == peer->procptr) 24554359Sroberto return; 246182007Sroberto 24754359Sroberto clktype = peer->refclktype; 24854359Sroberto unit = peer->refclkunit; 24954359Sroberto if (refclock_conf[clktype]->clock_shutdown != noentry) 25054359Sroberto (refclock_conf[clktype]->clock_shutdown)(unit, peer); 25154359Sroberto free(peer->procptr); 252290000Sglebius peer->procptr = NULL; 25354359Sroberto} 25454359Sroberto 25554359Sroberto 25654359Sroberto/* 257182007Sroberto * refclock_timer - called once per second for housekeeping. 258182007Sroberto */ 259182007Srobertovoid 260182007Srobertorefclock_timer( 261290000Sglebius struct peer *p 262182007Sroberto ) 263182007Sroberto{ 264290000Sglebius struct refclockproc * pp; 265290000Sglebius int unit; 266182007Sroberto 267290000Sglebius unit = p->refclkunit; 268290000Sglebius pp = p->procptr; 269290000Sglebius if (pp->conf->clock_timer != noentry) 270290000Sglebius (*pp->conf->clock_timer)(unit, p); 271290000Sglebius if (pp->action != NULL && pp->nextaction <= current_time) 272290000Sglebius (*pp->action)(p); 273182007Sroberto} 274182007Sroberto 275182007Sroberto 276182007Sroberto/* 27754359Sroberto * refclock_transmit - simulate the transmit procedure 27854359Sroberto * 27954359Sroberto * This routine implements the NTP transmit procedure for a reference 28054359Sroberto * clock. This provides a mechanism to call the driver at the NTP poll 28154359Sroberto * interval, as well as provides a reachability mechanism to detect a 28254359Sroberto * broken radio or other madness. 28354359Sroberto */ 28454359Srobertovoid 28554359Srobertorefclock_transmit( 28654359Sroberto struct peer *peer /* peer structure pointer */ 28754359Sroberto ) 28854359Sroberto{ 28954359Sroberto u_char clktype; 29054359Sroberto int unit; 29154359Sroberto 29254359Sroberto clktype = peer->refclktype; 29354359Sroberto unit = peer->refclkunit; 29454359Sroberto peer->sent++; 295182007Sroberto get_systime(&peer->xmt); 29654359Sroberto 29754359Sroberto /* 29854359Sroberto * This is a ripoff of the peer transmit routine, but 29954359Sroberto * specialized for reference clocks. We do a little less 30054359Sroberto * protocol here and call the driver-specific transmit routine. 30154359Sroberto */ 30254359Sroberto if (peer->burst == 0) { 30354359Sroberto u_char oreach; 30454359Sroberto#ifdef DEBUG 30554359Sroberto if (debug) 30654359Sroberto printf("refclock_transmit: at %ld %s\n", 307132451Sroberto current_time, stoa(&(peer->srcadr))); 30854359Sroberto#endif 30954359Sroberto 31054359Sroberto /* 31154359Sroberto * Update reachability and poll variables like the 31254359Sroberto * network code. 31354359Sroberto */ 314290000Sglebius oreach = peer->reach & 0xfe; 31582498Sroberto peer->reach <<= 1; 316290000Sglebius if (!(peer->reach & 0x0f)) 317290000Sglebius clock_filter(peer, 0., 0., MAXDISPERSE); 318182007Sroberto peer->outdate = current_time; 31982498Sroberto if (!peer->reach) { 32082498Sroberto if (oreach) { 321290000Sglebius report_event(PEVNT_UNREACH, peer, NULL); 32254359Sroberto peer->timereachable = current_time; 32354359Sroberto } 32454359Sroberto } else { 32554359Sroberto if (peer->flags & FLAG_BURST) 32654359Sroberto peer->burst = NSTAGE; 32754359Sroberto } 328182007Sroberto } else { 329182007Sroberto peer->burst--; 33054359Sroberto } 33154359Sroberto if (refclock_conf[clktype]->clock_poll != noentry) 33254359Sroberto (refclock_conf[clktype]->clock_poll)(unit, peer); 333182007Sroberto poll_update(peer, peer->hpoll); 33454359Sroberto} 33554359Sroberto 33654359Sroberto 33754359Sroberto/* 33854359Sroberto * Compare two doubles - used with qsort() 33954359Sroberto */ 34054359Srobertostatic int 34154359Srobertorefclock_cmpl_fp( 34254359Sroberto const void *p1, 34354359Sroberto const void *p2 34454359Sroberto ) 34554359Sroberto{ 34654359Sroberto const double *dp1 = (const double *)p1; 34754359Sroberto const double *dp2 = (const double *)p2; 34854359Sroberto 34954359Sroberto if (*dp1 < *dp2) 350290000Sglebius return -1; 35154359Sroberto if (*dp1 > *dp2) 352290000Sglebius return 1; 353290000Sglebius return 0; 35454359Sroberto} 355182007Sroberto 356182007Sroberto 35754359Sroberto/* 35854359Sroberto * refclock_process_offset - update median filter 35954359Sroberto * 36082498Sroberto * This routine uses the given offset and timestamps to construct a new 36182498Sroberto * entry in the median filter circular buffer. Samples that overflow the 36282498Sroberto * filter are quietly discarded. 36354359Sroberto */ 36454359Srobertovoid 36554359Srobertorefclock_process_offset( 366132451Sroberto struct refclockproc *pp, /* refclock structure pointer */ 367132451Sroberto l_fp lasttim, /* last timecode timestamp */ 368132451Sroberto l_fp lastrec, /* last receive timestamp */ 36954359Sroberto double fudge 37054359Sroberto ) 37154359Sroberto{ 372132451Sroberto l_fp lftemp; 37354359Sroberto double doffset; 37454359Sroberto 37554359Sroberto pp->lastrec = lastrec; 376132451Sroberto lftemp = lasttim; 377132451Sroberto L_SUB(&lftemp, &lastrec); 378132451Sroberto LFPTOD(&lftemp, doffset); 37954359Sroberto SAMPLE(doffset + fudge); 38054359Sroberto} 38154359Sroberto 382182007Sroberto 38354359Sroberto/* 38454359Sroberto * refclock_process - process a sample from the clock 385290000Sglebius * refclock_process_f - refclock_process with other than time1 fudge 38654359Sroberto * 38754359Sroberto * This routine converts the timecode in the form days, hours, minutes, 38854359Sroberto * seconds and milliseconds/microseconds to internal timestamp format, 38954359Sroberto * then constructs a new entry in the median filter circular buffer. 39054359Sroberto * Return success (1) if the data are correct and consistent with the 39154359Sroberto * converntional calendar. 392182007Sroberto * 393182007Sroberto * Important for PPS users: Normally, the pp->lastrec is set to the 394182007Sroberto * system time when the on-time character is received and the pp->year, 395182007Sroberto * ..., pp->second decoded and the seconds fraction pp->nsec in 396182007Sroberto * nanoseconds). When a PPS offset is available, pp->nsec is forced to 397182007Sroberto * zero and the fraction for pp->lastrec is set to the PPS offset. 398182007Sroberto */ 39954359Srobertoint 400290000Sglebiusrefclock_process_f( 401290000Sglebius struct refclockproc *pp, /* refclock structure pointer */ 402290000Sglebius double fudge 40354359Sroberto ) 40454359Sroberto{ 405132451Sroberto l_fp offset, ltemp; 40654359Sroberto 40754359Sroberto /* 40854359Sroberto * Compute the timecode timestamp from the days, hours, minutes, 40954359Sroberto * seconds and milliseconds/microseconds of the timecode. Use 41054359Sroberto * clocktime() for the aggregate seconds and the msec/usec for 41154359Sroberto * the fraction, when present. Note that this code relies on the 41254359Sroberto * filesystem time for the years and does not use the years of 41354359Sroberto * the timecode. 41454359Sroberto */ 41554359Sroberto if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 41654359Sroberto pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 41754359Sroberto return (0); 418182007Sroberto 419132451Sroberto offset.l_uf = 0; 420132451Sroberto DTOLFP(pp->nsec / 1e9, <emp); 421132451Sroberto L_ADD(&offset, <emp); 422290000Sglebius refclock_process_offset(pp, offset, pp->lastrec, fudge); 42354359Sroberto return (1); 42454359Sroberto} 42554359Sroberto 426182007Sroberto 427290000Sglebiusint 428290000Sglebiusrefclock_process( 429290000Sglebius struct refclockproc *pp /* refclock structure pointer */ 430290000Sglebius) 431290000Sglebius{ 432290000Sglebius return refclock_process_f(pp, pp->fudgetime1); 433290000Sglebius} 434290000Sglebius 435290000Sglebius 43654359Sroberto/* 43754359Sroberto * refclock_sample - process a pile of samples from the clock 43854359Sroberto * 43954359Sroberto * This routine implements a recursive median filter to suppress spikes 44054359Sroberto * in the data, as well as determine a performance statistic. It 441182007Sroberto * calculates the mean offset and RMS jitter. A time adjustment 44282498Sroberto * fudgetime1 can be added to the final offset to compensate for various 44382498Sroberto * systematic errors. The routine returns the number of samples 44482498Sroberto * processed, which could be zero. 44554359Sroberto */ 44654359Srobertostatic int 44754359Srobertorefclock_sample( 448132451Sroberto struct refclockproc *pp /* refclock structure pointer */ 44954359Sroberto ) 45054359Sroberto{ 451290000Sglebius size_t i, j, k, m, n; 452182007Sroberto double off[MAXSTAGE]; 453182007Sroberto double offset; 45454359Sroberto 45554359Sroberto /* 45654359Sroberto * Copy the raw offsets and sort into ascending order. Don't do 45754359Sroberto * anything if the buffer is empty. 45854359Sroberto */ 459132451Sroberto n = 0; 460132451Sroberto while (pp->codeproc != pp->coderecv) { 461132451Sroberto pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 462132451Sroberto off[n] = pp->filter[pp->codeproc]; 463132451Sroberto n++; 464132451Sroberto } 465132451Sroberto if (n == 0) 46654359Sroberto return (0); 467182007Sroberto 46854359Sroberto if (n > 1) 469290000Sglebius qsort(off, n, sizeof(off[0]), refclock_cmpl_fp); 47054359Sroberto 47154359Sroberto /* 47254359Sroberto * Reject the furthest from the median of the samples until 47354359Sroberto * approximately 60 percent of the samples remain. 47454359Sroberto */ 47554359Sroberto i = 0; j = n; 476182007Sroberto m = n - (n * 4) / 10; 47782498Sroberto while ((j - i) > m) { 47854359Sroberto offset = off[(j + i) / 2]; 47954359Sroberto if (off[j - 1] - offset < offset - off[i]) 48054359Sroberto i++; /* reject low end */ 48154359Sroberto else 48254359Sroberto j--; /* reject high end */ 48354359Sroberto } 48454359Sroberto 48554359Sroberto /* 48682498Sroberto * Determine the offset and jitter. 48754359Sroberto */ 488182007Sroberto pp->offset = 0; 489182007Sroberto pp->jitter = 0; 490182007Sroberto for (k = i; k < j; k++) { 491182007Sroberto pp->offset += off[k]; 492182007Sroberto if (k > i) 493182007Sroberto pp->jitter += SQUARE(off[k] - off[k - 1]); 494182007Sroberto } 495182007Sroberto pp->offset /= m; 496182007Sroberto pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision)); 49754359Sroberto#ifdef DEBUG 49854359Sroberto if (debug) 49954359Sroberto printf( 50082498Sroberto "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 501290000Sglebius (int)n, pp->offset, pp->disp, pp->jitter); 50254359Sroberto#endif 503290000Sglebius return (int)n; 50454359Sroberto} 50554359Sroberto 50654359Sroberto 50754359Sroberto/* 50854359Sroberto * refclock_receive - simulate the receive and packet procedures 50954359Sroberto * 51054359Sroberto * This routine simulates the NTP receive and packet procedures for a 51154359Sroberto * reference clock. This provides a mechanism in which the ordinary NTP 51254359Sroberto * filter, selection and combining algorithms can be used to suppress 51354359Sroberto * misbehaving radios and to mitigate between them when more than one is 51454359Sroberto * available for backup. 51554359Sroberto */ 51654359Srobertovoid 51754359Srobertorefclock_receive( 51854359Sroberto struct peer *peer /* peer structure pointer */ 51954359Sroberto ) 52054359Sroberto{ 52154359Sroberto struct refclockproc *pp; 52254359Sroberto 52354359Sroberto#ifdef DEBUG 52454359Sroberto if (debug) 52554359Sroberto printf("refclock_receive: at %lu %s\n", 526132451Sroberto current_time, stoa(&peer->srcadr)); 52754359Sroberto#endif 52854359Sroberto 52954359Sroberto /* 53054359Sroberto * Do a little sanity dance and update the peer structure. Groom 53154359Sroberto * the median filter samples and give the data to the clock 53254359Sroberto * filter. 53354359Sroberto */ 53454359Sroberto pp = peer->procptr; 53554359Sroberto peer->leap = pp->leap; 536182007Sroberto if (peer->leap == LEAP_NOTINSYNC) 53754359Sroberto return; 538182007Sroberto 539182007Sroberto peer->received++; 540182007Sroberto peer->timereceived = current_time; 541182007Sroberto if (!peer->reach) { 542290000Sglebius report_event(PEVNT_REACH, peer, NULL); 543182007Sroberto peer->timereachable = current_time; 54454359Sroberto } 54554359Sroberto peer->reach |= 1; 546132451Sroberto peer->reftime = pp->lastref; 547290000Sglebius peer->aorg = pp->lastrec; 548290000Sglebius peer->rootdisp = pp->disp; 549290000Sglebius get_systime(&peer->dst); 55054359Sroberto if (!refclock_sample(pp)) 55154359Sroberto return; 552182007Sroberto 55382498Sroberto clock_filter(peer, pp->offset, 0., pp->jitter); 554290000Sglebius if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != 555290000Sglebius NULL) { 556290000Sglebius if (sys_peer->refclktype == REFCLK_ATOM_PPS && 557290000Sglebius peer->refclktype != REFCLK_ATOM_PPS) 55882498Sroberto pp->fudgetime1 -= pp->offset * FUDGEFAC; 55982498Sroberto } 56054359Sroberto} 56154359Sroberto 562182007Sroberto 56354359Sroberto/* 56454359Sroberto * refclock_gtlin - groom next input line and extract timestamp 56554359Sroberto * 56654359Sroberto * This routine processes the timecode received from the clock and 567182007Sroberto * strips the parity bit and control characters. It returns the number 568182007Sroberto * of characters in the line followed by a NULL character ('\0'), which 569182007Sroberto * is not included in the count. In case of an empty line, the previous 570182007Sroberto * line is preserved. 57154359Sroberto */ 57254359Srobertoint 57354359Srobertorefclock_gtlin( 57454359Sroberto struct recvbuf *rbufp, /* receive buffer pointer */ 575182007Sroberto char *lineptr, /* current line pointer */ 576182007Sroberto int bmax, /* remaining characters in line */ 577182007Sroberto l_fp *tsptr /* pointer to timestamp returned */ 57854359Sroberto ) 57954359Sroberto{ 580290000Sglebius const char *sp, *spend; 581290000Sglebius char *dp, *dpend; 582290000Sglebius int dlen; 58354359Sroberto 584290000Sglebius if (bmax <= 0) 585290000Sglebius return (0); 586182007Sroberto 587290000Sglebius dp = lineptr; 588290000Sglebius dpend = dp + bmax - 1; /* leave room for NUL pad */ 589290000Sglebius sp = (const char *)rbufp->recv_buffer; 590290000Sglebius spend = sp + rbufp->recv_length; 591290000Sglebius 592290000Sglebius while (sp != spend && dp != dpend) { 593290000Sglebius char c; 594290000Sglebius 595290000Sglebius c = *sp++ & 0x7f; 596182007Sroberto if (c >= 0x20 && c < 0x7f) 597182007Sroberto *dp++ = c; 598182007Sroberto } 599290000Sglebius /* Get length of data written to the destination buffer. If 600290000Sglebius * zero, do *not* place a NUL byte to preserve the previous 601290000Sglebius * buffer content. 602290000Sglebius */ 603290000Sglebius dlen = dp - lineptr; 604290000Sglebius if (dlen) 605290000Sglebius *dp = '\0'; 606290000Sglebius *tsptr = rbufp->recv_time; 607290000Sglebius DPRINTF(2, ("refclock_gtlin: fd %d time %s timecode %d %s\n", 608290000Sglebius rbufp->fd, ulfptoa(&rbufp->recv_time, 6), dlen, 609290000Sglebius (dlen != 0) 610290000Sglebius ? lineptr 611290000Sglebius : "")); 612290000Sglebius return (dlen); 613182007Sroberto} 614182007Sroberto 615182007Sroberto 616182007Sroberto/* 617182007Sroberto * refclock_gtraw - get next line/chunk of data 618182007Sroberto * 619182007Sroberto * This routine returns the raw data received from the clock in both 620182007Sroberto * canonical or raw modes. The terminal interface routines map CR to LF. 621182007Sroberto * In canonical mode this results in two lines, one containing data 622182007Sroberto * followed by LF and another containing only LF. In raw mode the 623182007Sroberto * interface routines can deliver arbitraty chunks of data from one 624182007Sroberto * character to a maximum specified by the calling routine. In either 625182007Sroberto * mode the routine returns the number of characters in the line 626182007Sroberto * followed by a NULL character ('\0'), which is not included in the 627182007Sroberto * count. 628182007Sroberto * 629290000Sglebius * *tsptr receives a copy of the buffer timestamp. 630182007Sroberto */ 631182007Srobertoint 632182007Srobertorefclock_gtraw( 633182007Sroberto struct recvbuf *rbufp, /* receive buffer pointer */ 634182007Sroberto char *lineptr, /* current line pointer */ 635182007Sroberto int bmax, /* remaining characters in line */ 636182007Sroberto l_fp *tsptr /* pointer to timestamp returned */ 637182007Sroberto ) 638182007Sroberto{ 639290000Sglebius if (bmax <= 0) 640290000Sglebius return (0); 641290000Sglebius bmax -= 1; /* leave room for trailing NUL */ 642290000Sglebius if (bmax > rbufp->recv_length) 643290000Sglebius bmax = rbufp->recv_length; 644290000Sglebius memcpy(lineptr, rbufp->recv_buffer, bmax); 645290000Sglebius lineptr[bmax] = '\0'; 646182007Sroberto 647290000Sglebius *tsptr = rbufp->recv_time; 648290000Sglebius DPRINTF(2, ("refclock_gtraw: fd %d time %s timecode %d %s\n", 649290000Sglebius rbufp->fd, ulfptoa(&rbufp->recv_time, 6), bmax, 650290000Sglebius lineptr)); 651290000Sglebius return (bmax); 652290000Sglebius} 653290000Sglebius 654290000Sglebius 655290000Sglebius/* 656290000Sglebius * indicate_refclock_packet() 657290000Sglebius * 658290000Sglebius * Passes a fragment of refclock input read from the device to the 659290000Sglebius * driver direct input routine, which may consume it (batch it for 660290000Sglebius * queuing once a logical unit is assembled). If it is not so 661290000Sglebius * consumed, queue it for the driver's receive entrypoint. 662290000Sglebius * 663290000Sglebius * The return value is TRUE if the data has been consumed as a fragment 664290000Sglebius * and should not be counted as a received packet. 665290000Sglebius */ 666290000Sglebiusint 667290000Sglebiusindicate_refclock_packet( 668290000Sglebius struct refclockio * rio, 669290000Sglebius struct recvbuf * rb 670290000Sglebius ) 671290000Sglebius{ 672290000Sglebius /* Does this refclock use direct input routine? */ 673290000Sglebius if (rio->io_input != NULL && (*rio->io_input)(rb) == 0) { 674290000Sglebius /* 675290000Sglebius * data was consumed - nothing to pass up 676290000Sglebius * into block input machine 677290000Sglebius */ 678290000Sglebius freerecvbuf(rb); 679290000Sglebius 680290000Sglebius return TRUE; 68154359Sroberto } 682290000Sglebius add_full_recv_buffer(rb); 68354359Sroberto 684290000Sglebius return FALSE; 685290000Sglebius} 686290000Sglebius 687290000Sglebius 688290000Sglebius/* 689290000Sglebius * process_refclock_packet() 690290000Sglebius * 691290000Sglebius * Used for deferred processing of 'io_input' on systems where threading 692290000Sglebius * is used (notably Windows). This is acting as a trampoline to make the 693290000Sglebius * real calls to the refclock functions. 694290000Sglebius */ 695290000Sglebius#ifdef HAVE_IO_COMPLETION_PORT 696290000Sglebiusvoid 697290000Sglebiusprocess_refclock_packet( 698290000Sglebius struct recvbuf * rb 699290000Sglebius ) 700290000Sglebius{ 701290000Sglebius struct refclockio * rio; 702290000Sglebius 703290000Sglebius /* get the refclockio structure from the receive buffer */ 704290000Sglebius rio = &rb->recv_peer->procptr->io; 705290000Sglebius 706290000Sglebius /* call 'clock_recv' if either there is no input function or the 707290000Sglebius * raw input function tells us to feed the packet to the 708290000Sglebius * receiver. 70954359Sroberto */ 710290000Sglebius if (rio->io_input == NULL || (*rio->io_input)(rb) != 0) { 711290000Sglebius rio->recvcount++; 712290000Sglebius packets_received++; 713310419Sdelphij handler_pkts++; 714290000Sglebius (*rio->clock_recv)(rb); 715290000Sglebius } 71654359Sroberto} 717290000Sglebius#endif /* HAVE_IO_COMPLETION_PORT */ 71854359Sroberto 719182007Sroberto 72054359Sroberto/* 72154359Sroberto * The following code does not apply to WINNT & VMS ... 72254359Sroberto */ 723290000Sglebius#if !defined(SYS_VXWORKS) && !defined(SYS_WINNT) 72454359Sroberto#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 72554359Sroberto 72654359Sroberto/* 72754359Sroberto * refclock_open - open serial port for reference clock 72854359Sroberto * 72954359Sroberto * This routine opens a serial port for I/O and sets default options. It 730290000Sglebius * returns the file descriptor if successful, or logs an error and 731290000Sglebius * returns -1. 73254359Sroberto */ 73354359Srobertoint 73454359Srobertorefclock_open( 735293894Sglebius const char *dev, /* device name pointer */ 736293894Sglebius u_int speed, /* serial port speed (code) */ 737293894Sglebius u_int lflags /* line discipline flags */ 73854359Sroberto ) 73954359Sroberto{ 740182007Sroberto int fd; 741182007Sroberto int omode; 742290000Sglebius#ifdef O_NONBLOCK 743290000Sglebius char trash[128]; /* litter bin for old input data */ 744290000Sglebius#endif 74554359Sroberto 74654359Sroberto /* 74754359Sroberto * Open serial port and set default options 74854359Sroberto */ 74982498Sroberto omode = O_RDWR; 75054359Sroberto#ifdef O_NONBLOCK 75182498Sroberto omode |= O_NONBLOCK; 75282498Sroberto#endif 75382498Sroberto#ifdef O_NOCTTY 75482498Sroberto omode |= O_NOCTTY; 75582498Sroberto#endif 75682498Sroberto 75782498Sroberto fd = open(dev, omode, 0777); 758290000Sglebius /* refclock_open() long returned 0 on failure, avoid it. */ 759290000Sglebius if (0 == fd) { 760290000Sglebius fd = dup(0); 761290000Sglebius SAVE_ERRNO( 762290000Sglebius close(0); 763290000Sglebius ) 764290000Sglebius } 76582498Sroberto if (fd < 0) { 766290000Sglebius SAVE_ERRNO( 767290000Sglebius msyslog(LOG_ERR, "refclock_open %s: %m", dev); 768290000Sglebius ) 769290000Sglebius return -1; 77054359Sroberto } 771182007Sroberto if (!refclock_setup(fd, speed, lflags)) { 772182007Sroberto close(fd); 773290000Sglebius return -1; 774182007Sroberto } 775182007Sroberto if (!refclock_ioctl(fd, lflags)) { 776182007Sroberto close(fd); 777290000Sglebius return -1; 778182007Sroberto } 779290000Sglebius#ifdef O_NONBLOCK 780290000Sglebius /* 781290000Sglebius * We want to make sure there is no pending trash in the input 782290000Sglebius * buffer. Since we have non-blocking IO available, this is a 783290000Sglebius * good moment to read and dump all available outdated stuff 784290000Sglebius * that might have become toxic for the driver. 785290000Sglebius */ 786290000Sglebius while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR) 787290000Sglebius /*NOP*/; 788290000Sglebius#endif 789290000Sglebius return fd; 790182007Sroberto} 79154359Sroberto 792290000Sglebius 793182007Sroberto/* 794182007Sroberto * refclock_setup - initialize terminal interface structure 795182007Sroberto */ 796182007Srobertoint 797182007Srobertorefclock_setup( 798182007Sroberto int fd, /* file descriptor */ 799182007Sroberto u_int speed, /* serial port speed (code) */ 800182007Sroberto u_int lflags /* line discipline flags */ 801182007Sroberto ) 802182007Sroberto{ 803182007Sroberto int i; 804182007Sroberto TTY ttyb, *ttyp; 80582498Sroberto 80682498Sroberto /* 807182007Sroberto * By default, the serial line port is initialized in canonical 808182007Sroberto * (line-oriented) mode at specified line speed, 8 bits and no 809182007Sroberto * parity. LF ends the line and CR is mapped to LF. The break, 810182007Sroberto * erase and kill functions are disabled. There is a different 811182007Sroberto * section for each terminal interface, as selected at compile 812182007Sroberto * time. The flag bits can be used to set raw mode and echo. 81354359Sroberto */ 81454359Sroberto ttyp = &ttyb; 815182007Sroberto#ifdef HAVE_TERMIOS 81654359Sroberto 81754359Sroberto /* 81854359Sroberto * POSIX serial line parameters (termios interface) 81954359Sroberto */ 82054359Sroberto if (tcgetattr(fd, ttyp) < 0) { 821290000Sglebius SAVE_ERRNO( 822290000Sglebius msyslog(LOG_ERR, 823290000Sglebius "refclock_setup fd %d tcgetattr: %m", 824290000Sglebius fd); 825290000Sglebius ) 826290000Sglebius return FALSE; 82754359Sroberto } 82854359Sroberto 82954359Sroberto /* 83054359Sroberto * Set canonical mode and local connection; set specified speed, 83154359Sroberto * 8 bits and no parity; map CR to NL; ignore break. 83254359Sroberto */ 833182007Sroberto if (speed) { 834182007Sroberto u_int ltemp = 0; 835182007Sroberto 836182007Sroberto ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 837182007Sroberto ttyp->c_oflag = 0; 838182007Sroberto ttyp->c_cflag = CS8 | CLOCAL | CREAD; 839182007Sroberto if (lflags & LDISC_7O1) { 840182007Sroberto /* HP Z3801A needs 7-bit, odd parity */ 841290000Sglebius ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD; 842182007Sroberto } 843182007Sroberto cfsetispeed(&ttyb, speed); 844182007Sroberto cfsetospeed(&ttyb, speed); 845182007Sroberto for (i = 0; i < NCCS; ++i) 846182007Sroberto ttyp->c_cc[i] = '\0'; 847182007Sroberto 848182007Sroberto#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 849182007Sroberto 850182007Sroberto /* 851182007Sroberto * If we have modem control, check to see if modem leads 852182007Sroberto * are active; if so, set remote connection. This is 853182007Sroberto * necessary for the kernel pps mods to work. 854182007Sroberto */ 855182007Sroberto if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 856182007Sroberto msyslog(LOG_ERR, 857182007Sroberto "refclock_setup fd %d TIOCMGET: %m", fd); 858182007Sroberto#ifdef DEBUG 859182007Sroberto if (debug) 860182007Sroberto printf("refclock_setup fd %d modem status: 0x%x\n", 861182007Sroberto fd, ltemp); 862182007Sroberto#endif 863182007Sroberto if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE) 864182007Sroberto ttyp->c_cflag &= ~CLOCAL; 865182007Sroberto#endif /* TIOCMGET */ 86654359Sroberto } 86754359Sroberto 86854359Sroberto /* 869182007Sroberto * Set raw and echo modes. These can be changed on-fly. 87054359Sroberto */ 871182007Sroberto ttyp->c_lflag = ICANON; 872182007Sroberto if (lflags & LDISC_RAW) { 873182007Sroberto ttyp->c_lflag = 0; 87454359Sroberto ttyp->c_iflag = 0; 87554359Sroberto ttyp->c_cc[VMIN] = 1; 87654359Sroberto } 877182007Sroberto if (lflags & LDISC_ECHO) 878182007Sroberto ttyp->c_lflag |= ECHO; 87954359Sroberto if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 880290000Sglebius SAVE_ERRNO( 881290000Sglebius msyslog(LOG_ERR, 882290000Sglebius "refclock_setup fd %d TCSANOW: %m", 883290000Sglebius fd); 884290000Sglebius ) 885290000Sglebius return FALSE; 88654359Sroberto } 887290000Sglebius 888290000Sglebius /* 889290000Sglebius * flush input and output buffers to discard any outdated stuff 890290000Sglebius * that might have become toxic for the driver. Failing to do so 891290000Sglebius * is logged, but we keep our fingers crossed otherwise. 892290000Sglebius */ 893290000Sglebius if (tcflush(fd, TCIOFLUSH) < 0) 894290000Sglebius msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", 895290000Sglebius fd); 89654359Sroberto#endif /* HAVE_TERMIOS */ 89754359Sroberto 89854359Sroberto#ifdef HAVE_SYSV_TTYS 89954359Sroberto 90054359Sroberto /* 90154359Sroberto * System V serial line parameters (termio interface) 90254359Sroberto * 90354359Sroberto */ 90454359Sroberto if (ioctl(fd, TCGETA, ttyp) < 0) { 905290000Sglebius SAVE_ERRNO( 906290000Sglebius msyslog(LOG_ERR, 907290000Sglebius "refclock_setup fd %d TCGETA: %m", 908290000Sglebius fd); 909290000Sglebius ) 910290000Sglebius return FALSE; 91154359Sroberto } 91254359Sroberto 91354359Sroberto /* 91454359Sroberto * Set canonical mode and local connection; set specified speed, 91554359Sroberto * 8 bits and no parity; map CR to NL; ignore break. 91654359Sroberto */ 917182007Sroberto if (speed) { 918182007Sroberto u_int ltemp = 0; 91954359Sroberto 920182007Sroberto ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 921182007Sroberto ttyp->c_oflag = 0; 922182007Sroberto ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 923182007Sroberto for (i = 0; i < NCCS; ++i) 924182007Sroberto ttyp->c_cc[i] = '\0'; 925182007Sroberto 926182007Sroberto#if defined(TIOCMGET) && !defined(SCO5_CLOCK) 927182007Sroberto 928182007Sroberto /* 929182007Sroberto * If we have modem control, check to see if modem leads 930182007Sroberto * are active; if so, set remote connection. This is 931182007Sroberto * necessary for the kernel pps mods to work. 932182007Sroberto */ 933182007Sroberto if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 934182007Sroberto msyslog(LOG_ERR, 935182007Sroberto "refclock_setup fd %d TIOCMGET: %m", fd); 936182007Sroberto#ifdef DEBUG 937182007Sroberto if (debug) 938182007Sroberto printf("refclock_setup fd %d modem status: %x\n", 939182007Sroberto fd, ltemp); 940182007Sroberto#endif 941182007Sroberto if (ltemp & TIOCM_DSR) 942182007Sroberto ttyp->c_cflag &= ~CLOCAL; 943182007Sroberto#endif /* TIOCMGET */ 944182007Sroberto } 945182007Sroberto 94654359Sroberto /* 947182007Sroberto * Set raw and echo modes. These can be changed on-fly. 94854359Sroberto */ 949182007Sroberto ttyp->c_lflag = ICANON; 950182007Sroberto if (lflags & LDISC_RAW) { 951182007Sroberto ttyp->c_lflag = 0; 95254359Sroberto ttyp->c_iflag = 0; 953182007Sroberto ttyp->c_cc[VMIN] = 1; 95454359Sroberto } 95554359Sroberto if (ioctl(fd, TCSETA, ttyp) < 0) { 956290000Sglebius SAVE_ERRNO( 957290000Sglebius msyslog(LOG_ERR, 958290000Sglebius "refclock_setup fd %d TCSETA: %m", fd); 959290000Sglebius ) 960290000Sglebius return FALSE; 96154359Sroberto } 96254359Sroberto#endif /* HAVE_SYSV_TTYS */ 96354359Sroberto 96454359Sroberto#ifdef HAVE_BSD_TTYS 96554359Sroberto 96654359Sroberto /* 96754359Sroberto * 4.3bsd serial line parameters (sgttyb interface) 96854359Sroberto */ 96954359Sroberto if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { 970290000Sglebius SAVE_ERRNO( 971290000Sglebius msyslog(LOG_ERR, 972290000Sglebius "refclock_setup fd %d TIOCGETP: %m", 973290000Sglebius fd); 974290000Sglebius ) 975290000Sglebius return FALSE; 97654359Sroberto } 977182007Sroberto if (speed) 978182007Sroberto ttyp->sg_ispeed = ttyp->sg_ospeed = speed; 97954359Sroberto ttyp->sg_flags = EVENP | ODDP | CRMOD; 98054359Sroberto if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { 981290000Sglebius SAVE_ERRNO( 982290000Sglebius msyslog(LOG_ERR, "refclock_setup TIOCSETP: %m"); 983290000Sglebius ) 984290000Sglebius return FALSE; 98554359Sroberto } 98654359Sroberto#endif /* HAVE_BSD_TTYS */ 987182007Sroberto return(1); 98854359Sroberto} 98954359Sroberto#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 99054359Sroberto 991182007Sroberto 99254359Sroberto/* 99354359Sroberto * refclock_ioctl - set serial port control functions 99454359Sroberto * 99554359Sroberto * This routine attempts to hide the internal, system-specific details 99654359Sroberto * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 99754359Sroberto * (sgtty) interfaces with varying degrees of success. The routine sets 998290000Sglebius * up optional features such as tty_clk. The routine returns TRUE if 999290000Sglebius * successful. 100054359Sroberto */ 100154359Srobertoint 100254359Srobertorefclock_ioctl( 1003182007Sroberto int fd, /* file descriptor */ 1004182007Sroberto u_int lflags /* line discipline flags */ 100554359Sroberto ) 100654359Sroberto{ 1007182007Sroberto /* 1008290000Sglebius * simply return TRUE if no UNIX line discipline is supported 1009182007Sroberto */ 1010290000Sglebius DPRINTF(1, ("refclock_ioctl: fd %d flags 0x%x\n", fd, lflags)); 101154359Sroberto 1012290000Sglebius return TRUE; 101354359Sroberto} 1014290000Sglebius#endif /* !defined(SYS_VXWORKS) && !defined(SYS_WINNT) */ 101554359Sroberto 1016182007Sroberto 101754359Sroberto/* 101854359Sroberto * refclock_control - set and/or return clock values 101954359Sroberto * 102054359Sroberto * This routine is used mainly for debugging. It returns designated 102154359Sroberto * values from the interface structure that can be displayed using 102254359Sroberto * ntpdc and the clockstat command. It can also be used to initialize 102354359Sroberto * configuration variables, such as fudgetimes, fudgevalues, reference 102454359Sroberto * ID and stratum. 102554359Sroberto */ 102654359Srobertovoid 102754359Srobertorefclock_control( 1028290000Sglebius sockaddr_u *srcadr, 1029290000Sglebius const struct refclockstat *in, 103054359Sroberto struct refclockstat *out 103154359Sroberto ) 103254359Sroberto{ 103354359Sroberto struct peer *peer; 103454359Sroberto struct refclockproc *pp; 103554359Sroberto u_char clktype; 103654359Sroberto int unit; 103754359Sroberto 103854359Sroberto /* 103954359Sroberto * Check for valid address and running peer 104054359Sroberto */ 104154359Sroberto if (!ISREFCLOCKADR(srcadr)) 104254359Sroberto return; 1043182007Sroberto 104454359Sroberto clktype = (u_char)REFCLOCKTYPE(srcadr); 104554359Sroberto unit = REFCLOCKUNIT(srcadr); 1046182007Sroberto 1047290000Sglebius peer = findexistingpeer(srcadr, NULL, NULL, -1, 0); 1048182007Sroberto 1049290000Sglebius if (NULL == peer) 105082498Sroberto return; 1051182007Sroberto 1052290000Sglebius INSIST(peer->procptr != NULL); 105354359Sroberto pp = peer->procptr; 105454359Sroberto 105554359Sroberto /* 105654359Sroberto * Initialize requested data 105754359Sroberto */ 1058290000Sglebius if (in != NULL) { 105954359Sroberto if (in->haveflags & CLK_HAVETIME1) 106054359Sroberto pp->fudgetime1 = in->fudgetime1; 106154359Sroberto if (in->haveflags & CLK_HAVETIME2) 106254359Sroberto pp->fudgetime2 = in->fudgetime2; 106354359Sroberto if (in->haveflags & CLK_HAVEVAL1) 1064182007Sroberto peer->stratum = pp->stratum = (u_char)in->fudgeval1; 106554359Sroberto if (in->haveflags & CLK_HAVEVAL2) 1066182007Sroberto peer->refid = pp->refid = in->fudgeval2; 106754359Sroberto if (in->haveflags & CLK_HAVEFLAG1) { 106854359Sroberto pp->sloppyclockflag &= ~CLK_FLAG1; 106954359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG1; 107054359Sroberto } 107154359Sroberto if (in->haveflags & CLK_HAVEFLAG2) { 107254359Sroberto pp->sloppyclockflag &= ~CLK_FLAG2; 107354359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG2; 107454359Sroberto } 107554359Sroberto if (in->haveflags & CLK_HAVEFLAG3) { 107654359Sroberto pp->sloppyclockflag &= ~CLK_FLAG3; 107754359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG3; 107854359Sroberto } 107954359Sroberto if (in->haveflags & CLK_HAVEFLAG4) { 108054359Sroberto pp->sloppyclockflag &= ~CLK_FLAG4; 108154359Sroberto pp->sloppyclockflag |= in->flags & CLK_FLAG4; 108254359Sroberto } 108354359Sroberto } 108454359Sroberto 108554359Sroberto /* 108654359Sroberto * Readback requested data 108754359Sroberto */ 1088290000Sglebius if (out != NULL) { 1089290000Sglebius out->fudgeval1 = pp->stratum; 1090290000Sglebius out->fudgeval2 = pp->refid; 1091290000Sglebius out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; 109254359Sroberto out->fudgetime1 = pp->fudgetime1; 1093290000Sglebius if (0.0 != out->fudgetime1) 1094290000Sglebius out->haveflags |= CLK_HAVETIME1; 109554359Sroberto out->fudgetime2 = pp->fudgetime2; 1096290000Sglebius if (0.0 != out->fudgetime2) 1097290000Sglebius out->haveflags |= CLK_HAVETIME2; 109854359Sroberto out->flags = (u_char) pp->sloppyclockflag; 1099290000Sglebius if (CLK_FLAG1 & out->flags) 1100290000Sglebius out->haveflags |= CLK_HAVEFLAG1; 1101290000Sglebius if (CLK_FLAG2 & out->flags) 1102290000Sglebius out->haveflags |= CLK_HAVEFLAG2; 1103290000Sglebius if (CLK_FLAG3 & out->flags) 1104290000Sglebius out->haveflags |= CLK_HAVEFLAG3; 1105290000Sglebius if (CLK_FLAG4 & out->flags) 1106290000Sglebius out->haveflags |= CLK_HAVEFLAG4; 110754359Sroberto 110854359Sroberto out->timereset = current_time - pp->timestarted; 110954359Sroberto out->polls = pp->polls; 111054359Sroberto out->noresponse = pp->noreply; 111154359Sroberto out->badformat = pp->badformat; 111254359Sroberto out->baddata = pp->baddata; 111354359Sroberto 111454359Sroberto out->lastevent = pp->lastevent; 111554359Sroberto out->currentstatus = pp->currentstatus; 111654359Sroberto out->type = pp->type; 111754359Sroberto out->clockdesc = pp->clockdesc; 1118290000Sglebius out->lencode = (u_short)pp->lencode; 111954359Sroberto out->p_lastcode = pp->a_lastcode; 112054359Sroberto } 112154359Sroberto 112254359Sroberto /* 112354359Sroberto * Give the stuff to the clock 112454359Sroberto */ 112554359Sroberto if (refclock_conf[clktype]->clock_control != noentry) 112654359Sroberto (refclock_conf[clktype]->clock_control)(unit, in, out, peer); 112754359Sroberto} 112854359Sroberto 112954359Sroberto 113054359Sroberto/* 113154359Sroberto * refclock_buginfo - return debugging info 113254359Sroberto * 113354359Sroberto * This routine is used mainly for debugging. It returns designated 113454359Sroberto * values from the interface structure that can be displayed using 113554359Sroberto * ntpdc and the clkbug command. 113654359Sroberto */ 113754359Srobertovoid 113854359Srobertorefclock_buginfo( 1139290000Sglebius sockaddr_u *srcadr, /* clock address */ 114054359Sroberto struct refclockbug *bug /* output structure */ 114154359Sroberto ) 114254359Sroberto{ 114354359Sroberto struct peer *peer; 114454359Sroberto struct refclockproc *pp; 1145290000Sglebius int clktype; 114654359Sroberto int unit; 1147290000Sglebius unsigned u; 114854359Sroberto 114954359Sroberto /* 115054359Sroberto * Check for valid address and peer structure 115154359Sroberto */ 115254359Sroberto if (!ISREFCLOCKADR(srcadr)) 115354359Sroberto return; 1154182007Sroberto 115554359Sroberto clktype = (u_char) REFCLOCKTYPE(srcadr); 115654359Sroberto unit = REFCLOCKUNIT(srcadr); 1157182007Sroberto 1158290000Sglebius peer = findexistingpeer(srcadr, NULL, NULL, -1, 0); 1159290000Sglebius 1160290000Sglebius if (NULL == peer || NULL == peer->procptr) 116154359Sroberto return; 1162182007Sroberto 116354359Sroberto pp = peer->procptr; 116454359Sroberto 116554359Sroberto /* 116654359Sroberto * Copy structure values 116754359Sroberto */ 116854359Sroberto bug->nvalues = 8; 116954359Sroberto bug->svalues = 0x0000003f; 117054359Sroberto bug->values[0] = pp->year; 117154359Sroberto bug->values[1] = pp->day; 117254359Sroberto bug->values[2] = pp->hour; 117354359Sroberto bug->values[3] = pp->minute; 117454359Sroberto bug->values[4] = pp->second; 1175132451Sroberto bug->values[5] = pp->nsec; 117654359Sroberto bug->values[6] = pp->yearstart; 117754359Sroberto bug->values[7] = pp->coderecv; 117854359Sroberto bug->stimes = 0xfffffffc; 117954359Sroberto bug->times[0] = pp->lastref; 118054359Sroberto bug->times[1] = pp->lastrec; 1181290000Sglebius for (u = 2; u < bug->ntimes; u++) 1182290000Sglebius DTOLFP(pp->filter[u - 2], &bug->times[u]); 118354359Sroberto 118454359Sroberto /* 118554359Sroberto * Give the stuff to the clock 118654359Sroberto */ 118754359Sroberto if (refclock_conf[clktype]->clock_buginfo != noentry) 118854359Sroberto (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 118954359Sroberto} 119054359Sroberto 1191290000Sglebius 1192290000Sglebius#ifdef HAVE_PPSAPI 1193290000Sglebius/* 1194290000Sglebius * refclock_ppsapi - initialize/update ppsapi 1195290000Sglebius * 1196290000Sglebius * This routine is called after the fudge command to open the PPSAPI 1197290000Sglebius * interface for later parameter setting after the fudge command. 1198290000Sglebius */ 1199290000Sglebiusint 1200290000Sglebiusrefclock_ppsapi( 1201290000Sglebius int fddev, /* fd device */ 1202290000Sglebius struct refclock_atom *ap /* atom structure pointer */ 1203290000Sglebius ) 1204290000Sglebius{ 1205290000Sglebius if (ap->handle == 0) { 1206290000Sglebius if (time_pps_create(fddev, &ap->handle) < 0) { 1207290000Sglebius msyslog(LOG_ERR, 1208290000Sglebius "refclock_ppsapi: time_pps_create: %m"); 1209290000Sglebius return (0); 1210290000Sglebius } 1211310419Sdelphij ZERO(ap->ts); /* [Bug 2689] defined INIT state */ 1212290000Sglebius } 1213290000Sglebius return (1); 1214290000Sglebius} 1215290000Sglebius 1216290000Sglebius 1217290000Sglebius/* 1218290000Sglebius * refclock_params - set ppsapi parameters 1219290000Sglebius * 1220290000Sglebius * This routine is called to set the PPSAPI parameters after the fudge 1221290000Sglebius * command. 1222290000Sglebius */ 1223290000Sglebiusint 1224290000Sglebiusrefclock_params( 1225290000Sglebius int mode, /* mode bits */ 1226290000Sglebius struct refclock_atom *ap /* atom structure pointer */ 1227290000Sglebius ) 1228290000Sglebius{ 1229290000Sglebius ZERO(ap->pps_params); 1230290000Sglebius ap->pps_params.api_version = PPS_API_VERS_1; 1231290000Sglebius 1232290000Sglebius /* 1233290000Sglebius * Solaris serial ports provide PPS pulse capture only on the 1234290000Sglebius * assert edge. FreeBSD serial ports provide capture on the 1235290000Sglebius * clear edge, while FreeBSD parallel ports provide capture 1236290000Sglebius * on the assert edge. Your mileage may vary. 1237290000Sglebius */ 1238290000Sglebius if (mode & CLK_FLAG2) 1239290000Sglebius ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR; 1240290000Sglebius else 1241290000Sglebius ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT; 1242290000Sglebius if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) { 1243290000Sglebius msyslog(LOG_ERR, 1244290000Sglebius "refclock_params: time_pps_setparams: %m"); 1245290000Sglebius return (0); 1246290000Sglebius } 1247290000Sglebius 1248290000Sglebius /* 1249290000Sglebius * If flag3 is lit, select the kernel PPS if we can. 1250290000Sglebius */ 1251290000Sglebius if (mode & CLK_FLAG3) { 1252290000Sglebius if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS, 1253290000Sglebius ap->pps_params.mode & ~PPS_TSFMT_TSPEC, 1254290000Sglebius PPS_TSFMT_TSPEC) < 0) { 1255290000Sglebius msyslog(LOG_ERR, 1256290000Sglebius "refclock_params: time_pps_kcbind: %m"); 1257290000Sglebius return (0); 1258290000Sglebius } 1259290000Sglebius hardpps_enable = 1; 1260290000Sglebius } 1261290000Sglebius return (1); 1262290000Sglebius} 1263290000Sglebius 1264290000Sglebius 1265290000Sglebius/* 1266290000Sglebius * refclock_pps - called once per second 1267290000Sglebius * 1268290000Sglebius * This routine is called once per second. It snatches the PPS 1269290000Sglebius * timestamp from the kernel and saves the sign-extended fraction in 1270290000Sglebius * a circular buffer for processing at the next poll event. 1271290000Sglebius */ 1272290000Sglebiusint 1273290000Sglebiusrefclock_pps( 1274290000Sglebius struct peer *peer, /* peer structure pointer */ 1275290000Sglebius struct refclock_atom *ap, /* atom structure pointer */ 1276290000Sglebius int mode /* mode bits */ 1277290000Sglebius ) 1278290000Sglebius{ 1279290000Sglebius struct refclockproc *pp; 1280290000Sglebius pps_info_t pps_info; 1281290000Sglebius struct timespec timeout; 1282310419Sdelphij double dtemp, dcorr, trash; 1283290000Sglebius 1284290000Sglebius /* 1285290000Sglebius * We require the clock to be synchronized before setting the 1286290000Sglebius * parameters. When the parameters have been set, fetch the 1287290000Sglebius * most recent PPS timestamp. 1288290000Sglebius */ 1289290000Sglebius pp = peer->procptr; 1290290000Sglebius if (ap->handle == 0) 1291290000Sglebius return (0); 1292290000Sglebius 1293290000Sglebius if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) { 1294290000Sglebius if (refclock_params(pp->sloppyclockflag, ap) < 1) 1295290000Sglebius return (0); 1296290000Sglebius } 1297310419Sdelphij ZERO(timeout); 1298290000Sglebius ZERO(pps_info); 1299290000Sglebius if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info, 1300290000Sglebius &timeout) < 0) { 1301290000Sglebius refclock_report(peer, CEVNT_FAULT); 1302290000Sglebius return (0); 1303290000Sglebius } 1304310419Sdelphij timeout = ap->ts; /* save old timestamp for check */ 1305290000Sglebius if (ap->pps_params.mode & PPS_CAPTUREASSERT) 1306290000Sglebius ap->ts = pps_info.assert_timestamp; 1307290000Sglebius else if (ap->pps_params.mode & PPS_CAPTURECLEAR) 1308290000Sglebius ap->ts = pps_info.clear_timestamp; 1309290000Sglebius else 1310290000Sglebius return (0); 1311290000Sglebius 1312310419Sdelphij /* [Bug 2689] Discard the first sample we read -- if the PPS 1313310419Sdelphij * source is currently down / disconnected, we have read a 1314310419Sdelphij * potentially *very* stale value here. So if our old TS value 1315310419Sdelphij * is all-zero, we consider this sample unrealiable and drop it. 1316310419Sdelphij * 1317310419Sdelphij * Note 1: a better check would compare the PPS time stamp to 1318310419Sdelphij * the current system time and drop it if it's more than say 3s 1319310419Sdelphij * away. 1320310419Sdelphij * 1321310419Sdelphij * Note 2: If we ever again get an all-zero PPS sample, the next 1322310419Sdelphij * one will be discarded. This can happen every 136yrs and is 1323310419Sdelphij * unlikely to be ever observed. 1324310419Sdelphij */ 1325310419Sdelphij if (0 == (timeout.tv_sec | timeout.tv_nsec)) 1326310419Sdelphij return (0); 1327310419Sdelphij 1328310419Sdelphij /* If the PPS source fails to deliver a new sample between 1329310419Sdelphij * polls, it regurgitates the last sample. We do not want to 1330310419Sdelphij * process the same sample multiple times. 1331310419Sdelphij */ 1332290000Sglebius if (0 == memcmp(&timeout, &ap->ts, sizeof(timeout))) 1333290000Sglebius return (0); 1334290000Sglebius 1335290000Sglebius /* 1336310419Sdelphij * Convert to signed fraction offset, apply fudge and properly 1337310419Sdelphij * fold the correction into the [-0.5s,0.5s] range. Handle 1338310419Sdelphij * excessive fudge times, too. 1339290000Sglebius */ 1340310419Sdelphij dtemp = ap->ts.tv_nsec / 1e9; 1341310419Sdelphij dcorr = modf((pp->fudgetime1 - dtemp), &trash); 1342310419Sdelphij if (dcorr > 0.5) 1343310419Sdelphij dcorr -= 1.0; 1344310419Sdelphij else if (dcorr < -0.5) 1345310419Sdelphij dcorr += 1.0; 1346310419Sdelphij 1347310419Sdelphij /* phase gate check: avoid wobbling by +/-1s when too close to 1348310419Sdelphij * the switch-over point. We allow +/-400ms max phase deviation. 1349310419Sdelphij * The trade-off is clear: The smaller the limit, the less 1350310419Sdelphij * sensitive to sampling noise the clock becomes. OTOH the 1351310419Sdelphij * system must get into phase gate range by other means for the 1352310419Sdelphij * PPS clock to lock in. 1353310419Sdelphij */ 1354310419Sdelphij if (fabs(dcorr) > 0.4) 1355310419Sdelphij return (0); 1356310419Sdelphij 1357310419Sdelphij /* 1358310419Sdelphij * record this time stamp and stuff in median filter 1359310419Sdelphij */ 1360290000Sglebius pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970; 1361290000Sglebius pp->lastrec.l_uf = (u_int32)(dtemp * FRAC); 1362310419Sdelphij SAMPLE(dcorr); 1363310419Sdelphij 1364290000Sglebius#ifdef DEBUG 1365290000Sglebius if (debug > 1) 1366290000Sglebius printf("refclock_pps: %lu %f %f\n", current_time, 1367310419Sdelphij dcorr, pp->fudgetime1); 1368290000Sglebius#endif 1369290000Sglebius return (1); 1370290000Sglebius} 1371290000Sglebius#endif /* HAVE_PPSAPI */ 137254359Sroberto#endif /* REFCLOCK */ 1373