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, &ltemp);
421132451Sroberto	L_ADD(&offset, &ltemp);
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 *)&ltemp) < 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 *)&ltemp) < 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