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