xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_arbiter.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: refclock_arbiter.c,v 1.6 2024/08/18 20:47:18 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
5abb0f93cSkardel  *	Controlled Clock
6abb0f93cSkardel  */
7abb0f93cSkardel 
8abb0f93cSkardel #ifdef HAVE_CONFIG_H
9abb0f93cSkardel #include <config.h>
10abb0f93cSkardel #endif
11abb0f93cSkardel 
12abb0f93cSkardel #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
13abb0f93cSkardel 
14abb0f93cSkardel #include "ntpd.h"
15abb0f93cSkardel #include "ntp_io.h"
16abb0f93cSkardel #include "ntp_refclock.h"
17abb0f93cSkardel #include "ntp_stdlib.h"
18abb0f93cSkardel 
19abb0f93cSkardel #include <stdio.h>
20abb0f93cSkardel #include <ctype.h>
21abb0f93cSkardel 
22abb0f93cSkardel /*
23abb0f93cSkardel  * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
24abb0f93cSkardel  * The claimed accuracy of this clock is 100 ns relative to the PPS
25abb0f93cSkardel  * output when receiving four or more satellites.
26abb0f93cSkardel  *
27abb0f93cSkardel  * The receiver should be configured before starting the NTP daemon, in
28abb0f93cSkardel  * order to establish reliable position and operating conditions. It
29abb0f93cSkardel  * does not initiate surveying or hold mode. For use with NTP, the
30abb0f93cSkardel  * daylight savings time feature should be disables (D0 command) and the
31abb0f93cSkardel  * broadcast mode set to operate in UTC (BU command).
32abb0f93cSkardel  *
33abb0f93cSkardel  * The timecode format supported by this driver is selected by the poll
34abb0f93cSkardel  * sequence "B5", which initiates a line in the following format to be
35abb0f93cSkardel  * repeated once per second until turned off by the "B0" poll sequence.
36abb0f93cSkardel  *
37abb0f93cSkardel  * Format B5 (24 ASCII printing characters):
38abb0f93cSkardel  *
39abb0f93cSkardel  * <cr><lf>i yy ddd hh:mm:ss.000bbb
40abb0f93cSkardel  *
41abb0f93cSkardel  *	on-time = <cr>
42abb0f93cSkardel  *	i = synchronization flag (' ' = locked, '?' = unlocked)
43abb0f93cSkardel  *	yy = year of century
44abb0f93cSkardel  *	ddd = day of year
45abb0f93cSkardel  *	hh:mm:ss = hours, minutes, seconds
46abb0f93cSkardel  *	.000 = fraction of second (not used)
47abb0f93cSkardel  *	bbb = tailing spaces for fill
48abb0f93cSkardel  *
49abb0f93cSkardel  * The alarm condition is indicated by a '?' at i, which indicates the
50abb0f93cSkardel  * receiver is not synchronized. In normal operation, a line consisting
51abb0f93cSkardel  * of the timecode followed by the time quality character (TQ) followed
52abb0f93cSkardel  * by the receiver status string (SR) is written to the clockstats file.
53abb0f93cSkardel  * The time quality character is encoded in IEEE P1344 standard:
54abb0f93cSkardel  *
55abb0f93cSkardel  * Format TQ (IEEE P1344 estimated worst-case time quality)
56abb0f93cSkardel  *
57abb0f93cSkardel  *	0	clock locked, maximum accuracy
58abb0f93cSkardel  *	F	clock failure, time not reliable
59abb0f93cSkardel  *	4	clock unlocked, accuracy < 1 us
60abb0f93cSkardel  *	5	clock unlocked, accuracy < 10 us
61abb0f93cSkardel  *	6	clock unlocked, accuracy < 100 us
62abb0f93cSkardel  *	7	clock unlocked, accuracy < 1 ms
63abb0f93cSkardel  *	8	clock unlocked, accuracy < 10 ms
64abb0f93cSkardel  *	9	clock unlocked, accuracy < 100 ms
65abb0f93cSkardel  *	A	clock unlocked, accuracy < 1 s
66abb0f93cSkardel  *	B	clock unlocked, accuracy < 10 s
67abb0f93cSkardel  *
68abb0f93cSkardel  * The status string is encoded as follows:
69abb0f93cSkardel  *
70abb0f93cSkardel  * Format SR (25 ASCII printing characters)
71abb0f93cSkardel  *
72abb0f93cSkardel  *	V=vv S=ss T=t P=pdop E=ee
73abb0f93cSkardel  *
74abb0f93cSkardel  *	vv = satellites visible
75abb0f93cSkardel  *	ss = relative signal strength
76abb0f93cSkardel  *	t = satellites tracked
77abb0f93cSkardel  *	pdop = position dilution of precision (meters)
78abb0f93cSkardel  *	ee = hardware errors
79abb0f93cSkardel  *
80abb0f93cSkardel  * If flag4 is set, an additional line consisting of the receiver
81abb0f93cSkardel  * latitude (LA), longitude (LO), elevation (LH) (meters), and data
82abb0f93cSkardel  * buffer (DB) is written to this file. If channel B is enabled for
83abb0f93cSkardel  * deviation mode and connected to a 1-PPS signal, the last two numbers
84abb0f93cSkardel  * on the line are the deviation and standard deviation averaged over
85abb0f93cSkardel  * the last 15 seconds.
86abb0f93cSkardel  *
87abb0f93cSkardel  * PPS calibration fudge time1 .001240
88abb0f93cSkardel  */
89abb0f93cSkardel 
90abb0f93cSkardel /*
91abb0f93cSkardel  * Interface definitions
92abb0f93cSkardel  */
93abb0f93cSkardel #define	DEVICE		"/dev/gps%d" /* device name and unit */
94abb0f93cSkardel #define	SPEED232	B9600	/* uart speed (9600 baud) */
95abb0f93cSkardel #define	PRECISION	(-20)	/* precision assumed (about 1 us) */
96abb0f93cSkardel #define	REFID		"GPS "	/* reference ID */
97abb0f93cSkardel #define	DESCRIPTION	"Arbiter 1088A/B GPS Receiver" /* WRU */
98abb0f93cSkardel #define	LENARB		24	/* format B5 timecode length */
99abb0f93cSkardel #define MAXSTA		40	/* max length of status string */
100abb0f93cSkardel #define MAXPOS		80	/* max length of position string */
101abb0f93cSkardel 
102f003fb54Skardel #ifdef PRE_NTP420
103f003fb54Skardel #define MODE ttlmax
104f003fb54Skardel #else
105f003fb54Skardel #define MODE ttl
106f003fb54Skardel #endif
107f003fb54Skardel 
108f003fb54Skardel #define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
109f003fb54Skardel #define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
110f003fb54Skardel 
111abb0f93cSkardel /*
112abb0f93cSkardel  * ARB unit control structure
113abb0f93cSkardel  */
114abb0f93cSkardel struct arbunit {
115abb0f93cSkardel 	l_fp	laststamp;	/* last receive timestamp */
116abb0f93cSkardel 	int	tcswitch;	/* timecode switch/counter */
117abb0f93cSkardel 	char	qualchar;	/* IEEE P1344 quality (TQ command) */
118abb0f93cSkardel 	char	status[MAXSTA];	/* receiver status (SR command) */
119abb0f93cSkardel 	char	latlon[MAXPOS];	/* receiver position (lat/lon/alt) */
120abb0f93cSkardel };
121abb0f93cSkardel 
122abb0f93cSkardel /*
123abb0f93cSkardel  * Function prototypes
124abb0f93cSkardel  */
125abb0f93cSkardel static	int	arb_start	(int, struct peer *);
126abb0f93cSkardel static	void	arb_shutdown	(int, struct peer *);
127abb0f93cSkardel static	void	arb_receive	(struct recvbuf *);
128abb0f93cSkardel static	void	arb_poll	(int, struct peer *);
129abb0f93cSkardel 
130abb0f93cSkardel /*
131abb0f93cSkardel  * Transfer vector
132abb0f93cSkardel  */
133abb0f93cSkardel struct	refclock refclock_arbiter = {
134abb0f93cSkardel 	arb_start,		/* start up driver */
135abb0f93cSkardel 	arb_shutdown,		/* shut down driver */
136abb0f93cSkardel 	arb_poll,		/* transmit poll message */
137abb0f93cSkardel 	noentry,		/* not used (old arb_control) */
138abb0f93cSkardel 	noentry,		/* initialize driver (not used) */
139abb0f93cSkardel 	noentry,		/* not used (old arb_buginfo) */
140abb0f93cSkardel 	NOFLAGS			/* not used */
141abb0f93cSkardel };
142abb0f93cSkardel 
143abb0f93cSkardel 
144abb0f93cSkardel /*
145abb0f93cSkardel  * arb_start - open the devices and initialize data for processing
146abb0f93cSkardel  */
147abb0f93cSkardel static int
148abb0f93cSkardel arb_start(
149abb0f93cSkardel 	int unit,
150abb0f93cSkardel 	struct peer *peer
151abb0f93cSkardel 	)
152abb0f93cSkardel {
153abb0f93cSkardel 	register struct arbunit *up;
154abb0f93cSkardel 	struct refclockproc *pp;
155abb0f93cSkardel 	int fd;
156abb0f93cSkardel 	char device[20];
157abb0f93cSkardel 
158abb0f93cSkardel 	/*
159abb0f93cSkardel 	 * Open serial port. Use CLK line discipline, if available.
160abb0f93cSkardel 	 */
161f003fb54Skardel 	snprintf(device, sizeof(device), DEVICE, unit);
162*eabc0478Schristos 	fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_CLK);
1638585484eSchristos 	if (fd <= 0)
164abb0f93cSkardel 		return (0);
165abb0f93cSkardel 
166abb0f93cSkardel 	/*
167abb0f93cSkardel 	 * Allocate and initialize unit structure
168abb0f93cSkardel 	 */
1698585484eSchristos 	up = emalloc_zero(sizeof(*up));
170abb0f93cSkardel 	pp = peer->procptr;
171abb0f93cSkardel 	pp->io.clock_recv = arb_receive;
1728585484eSchristos 	pp->io.srcclock = peer;
173abb0f93cSkardel 	pp->io.datalen = 0;
174abb0f93cSkardel 	pp->io.fd = fd;
175abb0f93cSkardel 	if (!io_addclock(&pp->io)) {
176f003fb54Skardel 		close(fd);
177f003fb54Skardel 		pp->io.fd = -1;
178abb0f93cSkardel 		free(up);
179abb0f93cSkardel 		return (0);
180abb0f93cSkardel 	}
1818585484eSchristos 	pp->unitptr = up;
182abb0f93cSkardel 
183abb0f93cSkardel 	/*
184abb0f93cSkardel 	 * Initialize miscellaneous variables
185abb0f93cSkardel 	 */
186abb0f93cSkardel 	peer->precision = PRECISION;
187abb0f93cSkardel 	pp->clockdesc = DESCRIPTION;
188abb0f93cSkardel 	memcpy((char *)&pp->refid, REFID, 4);
189f003fb54Skardel 	if (peer->MODE > 1) {
190f003fb54Skardel 		msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
191f003fb54Skardel 		close(fd);
192f003fb54Skardel 		pp->io.fd = -1;
193f003fb54Skardel 		free(up);
194f003fb54Skardel 		return (0);
195f003fb54Skardel 	}
196f003fb54Skardel #ifdef DEBUG
197f003fb54Skardel 	if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
198f003fb54Skardel #endif
199*eabc0478Schristos 	refclock_write(peer, COMMAND_HALT_BCAST, 2, "HALT_BCAST");
200abb0f93cSkardel 	return (1);
201abb0f93cSkardel }
202abb0f93cSkardel 
203abb0f93cSkardel 
204abb0f93cSkardel /*
205abb0f93cSkardel  * arb_shutdown - shut down the clock
206abb0f93cSkardel  */
207abb0f93cSkardel static void
208abb0f93cSkardel arb_shutdown(
209abb0f93cSkardel 	int unit,
210abb0f93cSkardel 	struct peer *peer
211abb0f93cSkardel 	)
212abb0f93cSkardel {
213abb0f93cSkardel 	register struct arbunit *up;
214abb0f93cSkardel 	struct refclockproc *pp;
215abb0f93cSkardel 
216abb0f93cSkardel 	pp = peer->procptr;
2178585484eSchristos 	up = pp->unitptr;
218f003fb54Skardel 	if (-1 != pp->io.fd)
219abb0f93cSkardel 		io_closeclock(&pp->io);
220f003fb54Skardel 	if (NULL != up)
221abb0f93cSkardel 		free(up);
222abb0f93cSkardel }
223abb0f93cSkardel 
224abb0f93cSkardel 
225abb0f93cSkardel /*
226abb0f93cSkardel  * arb_receive - receive data from the serial interface
227abb0f93cSkardel  */
228abb0f93cSkardel static void
229abb0f93cSkardel arb_receive(
230abb0f93cSkardel 	struct recvbuf *rbufp
231abb0f93cSkardel 	)
232abb0f93cSkardel {
233abb0f93cSkardel 	register struct arbunit *up;
234abb0f93cSkardel 	struct refclockproc *pp;
235abb0f93cSkardel 	struct peer *peer;
236abb0f93cSkardel 	l_fp trtmp;
237abb0f93cSkardel 	int temp;
238abb0f93cSkardel 	u_char	syncchar;		/* synch indicator */
239abb0f93cSkardel 	char	tbuf[BMAX];		/* temp buffer */
240abb0f93cSkardel 
241abb0f93cSkardel 	/*
242abb0f93cSkardel 	 * Initialize pointers and read the timecode and timestamp
243abb0f93cSkardel 	 */
2448585484eSchristos 	peer = rbufp->recv_peer;
245abb0f93cSkardel 	pp = peer->procptr;
2468585484eSchristos 	up = pp->unitptr;
2478585484eSchristos 	temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp);
248abb0f93cSkardel 
249abb0f93cSkardel 	/*
250abb0f93cSkardel 	 * Note we get a buffer and timestamp for both a <cr> and <lf>,
251abb0f93cSkardel 	 * but only the <cr> timestamp is retained. The program first
252abb0f93cSkardel 	 * sends a TQ and expects the echo followed by the time quality
253abb0f93cSkardel 	 * character. It then sends a B5 starting the timecode broadcast
254abb0f93cSkardel 	 * and expects the echo followed some time later by the on-time
255abb0f93cSkardel 	 * character <cr> and then the <lf> beginning the timecode
256abb0f93cSkardel 	 * itself. Finally, at the <cr> beginning the next timecode at
257abb0f93cSkardel 	 * the next second, the program sends a B0 shutting down the
258abb0f93cSkardel 	 * timecode broadcast.
259abb0f93cSkardel 	 *
260abb0f93cSkardel 	 * If flag4 is set, the program snatches the latitude, longitude
261abb0f93cSkardel 	 * and elevation and writes it to the clockstats file.
262abb0f93cSkardel 	 */
263abb0f93cSkardel 	if (temp == 0)
264abb0f93cSkardel 		return;
265abb0f93cSkardel 
266abb0f93cSkardel 	pp->lastrec = up->laststamp;
267abb0f93cSkardel 	up->laststamp = trtmp;
268abb0f93cSkardel 	if (temp < 3)
269abb0f93cSkardel 		return;
270abb0f93cSkardel 
271abb0f93cSkardel 	if (up->tcswitch == 0) {
272abb0f93cSkardel 
273abb0f93cSkardel 		/*
274abb0f93cSkardel 		 * Collect statistics. If nothing is recogized, just
275abb0f93cSkardel 		 * ignore; sometimes the clock doesn't stop spewing
276abb0f93cSkardel 		 * timecodes for awhile after the B0 command.
277abb0f93cSkardel 		 *
278abb0f93cSkardel 		 * If flag4 is not set, send TQ, SR, B5. If flag4 is
279abb0f93cSkardel 		 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
280abb0f93cSkardel 		 * median filter is full, send B0.
281abb0f93cSkardel 		 */
282abb0f93cSkardel 		if (!strncmp(tbuf, "TQ", 2)) {
283abb0f93cSkardel 			up->qualchar = tbuf[2];
284*eabc0478Schristos 			refclock_write(peer, "SR", 2, "SR");
285abb0f93cSkardel 			return;
286abb0f93cSkardel 
287abb0f93cSkardel 		} else if (!strncmp(tbuf, "SR", 2)) {
2888585484eSchristos 			strlcpy(up->status, tbuf + 2,
2898585484eSchristos 				sizeof(up->status));
290abb0f93cSkardel 			if (pp->sloppyclockflag & CLK_FLAG4)
291*eabc0478Schristos 			    refclock_write(peer, "LA", 2, "LA");
292abb0f93cSkardel 			else
293*eabc0478Schristos 			    refclock_write(peer, COMMAND_START_BCAST, 2,
294*eabc0478Schristos 				COMMAND_START_BCAST);
295abb0f93cSkardel 			return;
296abb0f93cSkardel 
297abb0f93cSkardel 		} else if (!strncmp(tbuf, "LA", 2)) {
2988585484eSchristos 			strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon));
299*eabc0478Schristos 			refclock_write(peer, "LO", 2, "LO");
300abb0f93cSkardel 			return;
301abb0f93cSkardel 
302abb0f93cSkardel 		} else if (!strncmp(tbuf, "LO", 2)) {
3038585484eSchristos 			strlcat(up->latlon, " ", sizeof(up->latlon));
3048585484eSchristos 			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
305*eabc0478Schristos 			refclock_write(peer, "LH", 2, "LH");
306abb0f93cSkardel 			return;
307abb0f93cSkardel 
308abb0f93cSkardel 		} else if (!strncmp(tbuf, "LH", 2)) {
3098585484eSchristos 			strlcat(up->latlon, " ", sizeof(up->latlon));
3108585484eSchristos 			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
311*eabc0478Schristos 			refclock_write(peer, "DB", 2, "DB");
312abb0f93cSkardel 			return;
313abb0f93cSkardel 
314abb0f93cSkardel 		} else if (!strncmp(tbuf, "DB", 2)) {
3158585484eSchristos 			strlcat(up->latlon, " ", sizeof(up->latlon));
3168585484eSchristos 			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
317abb0f93cSkardel 			record_clock_stats(&peer->srcadr, up->latlon);
318abb0f93cSkardel #ifdef DEBUG
319abb0f93cSkardel 			if (debug)
320abb0f93cSkardel 				printf("arbiter: %s\n", up->latlon);
321abb0f93cSkardel #endif
322*eabc0478Schristos 			refclock_write(peer, COMMAND_START_BCAST, 2,
323*eabc0478Schristos 				       COMMAND_START_BCAST);
324abb0f93cSkardel 		}
325abb0f93cSkardel 	}
326abb0f93cSkardel 
327abb0f93cSkardel 	/*
328abb0f93cSkardel 	 * We get down to business, check the timecode format and decode
329abb0f93cSkardel 	 * its contents. If the timecode has valid length, but not in
330abb0f93cSkardel 	 * proper format, we declare bad format and exit. If the
331abb0f93cSkardel 	 * timecode has invalid length, which sometimes occurs when the
332abb0f93cSkardel 	 * B0 amputates the broadcast, we just quietly steal away. Note
333abb0f93cSkardel 	 * that the time quality character and receiver status string is
334abb0f93cSkardel 	 * tacked on the end for clockstats display.
335abb0f93cSkardel 	 */
336abb0f93cSkardel 	up->tcswitch++;
337abb0f93cSkardel 	if (up->tcswitch <= 1 || temp < LENARB)
338abb0f93cSkardel 		return;
339abb0f93cSkardel 
340abb0f93cSkardel 	/*
341abb0f93cSkardel 	 * Timecode format B5: "i yy ddd hh:mm:ss.000   "
342abb0f93cSkardel 	 */
3438585484eSchristos 	strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode));
344abb0f93cSkardel 	pp->a_lastcode[LENARB - 2] = up->qualchar;
3458585484eSchristos 	strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode));
346abb0f93cSkardel 	pp->lencode = strlen(pp->a_lastcode);
347abb0f93cSkardel 	syncchar = ' ';
348abb0f93cSkardel 	if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
349abb0f93cSkardel 	    &syncchar, &pp->year, &pp->day, &pp->hour,
350abb0f93cSkardel 	    &pp->minute, &pp->second) != 6) {
351abb0f93cSkardel 		refclock_report(peer, CEVNT_BADREPLY);
352*eabc0478Schristos 		refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST);
353abb0f93cSkardel 		return;
354abb0f93cSkardel 	}
355abb0f93cSkardel 
356abb0f93cSkardel 	/*
357abb0f93cSkardel 	 * We decode the clock dispersion from the time quality
358abb0f93cSkardel 	 * character.
359abb0f93cSkardel 	 */
360abb0f93cSkardel 	switch (up->qualchar) {
361abb0f93cSkardel 
362abb0f93cSkardel 	    case '0':		/* locked, max accuracy */
363abb0f93cSkardel 		pp->disp = 1e-7;
364abb0f93cSkardel 		pp->lastref = pp->lastrec;
365abb0f93cSkardel 		break;
366abb0f93cSkardel 
367abb0f93cSkardel 	    case '4':		/* unlock accuracy < 1 us */
368abb0f93cSkardel 		pp->disp = 1e-6;
369abb0f93cSkardel 		break;
370abb0f93cSkardel 
371abb0f93cSkardel 	    case '5':		/* unlock accuracy < 10 us */
372abb0f93cSkardel 		pp->disp = 1e-5;
373abb0f93cSkardel 		break;
374abb0f93cSkardel 
375abb0f93cSkardel 	    case '6':		/* unlock accuracy < 100 us */
376abb0f93cSkardel 		pp->disp = 1e-4;
377abb0f93cSkardel 		break;
378abb0f93cSkardel 
379abb0f93cSkardel 	    case '7':		/* unlock accuracy < 1 ms */
380abb0f93cSkardel 		pp->disp = .001;
381abb0f93cSkardel 		break;
382abb0f93cSkardel 
383abb0f93cSkardel 	    case '8':		/* unlock accuracy < 10 ms */
384abb0f93cSkardel 		pp->disp = .01;
385abb0f93cSkardel 		break;
386abb0f93cSkardel 
387abb0f93cSkardel 	    case '9':		/* unlock accuracy < 100 ms */
388abb0f93cSkardel 		pp->disp = .1;
389abb0f93cSkardel 		break;
390abb0f93cSkardel 
391abb0f93cSkardel 	    case 'A':		/* unlock accuracy < 1 s */
392abb0f93cSkardel 		pp->disp = 1;
393abb0f93cSkardel 		break;
394abb0f93cSkardel 
395abb0f93cSkardel 	    case 'B':		/* unlock accuracy < 10 s */
396abb0f93cSkardel 		pp->disp = 10;
397abb0f93cSkardel 		break;
398abb0f93cSkardel 
399abb0f93cSkardel 	    case 'F':		/* clock failure */
400abb0f93cSkardel 		pp->disp = MAXDISPERSE;
401abb0f93cSkardel 		refclock_report(peer, CEVNT_FAULT);
402*eabc0478Schristos 		refclock_write(peer, COMMAND_HALT_BCAST, 2,
403*eabc0478Schristos 			       COMMAND_HALT_BCAST);
404abb0f93cSkardel 		return;
405abb0f93cSkardel 
406abb0f93cSkardel 	    default:
407abb0f93cSkardel 		pp->disp = MAXDISPERSE;
408abb0f93cSkardel 		refclock_report(peer, CEVNT_BADREPLY);
409*eabc0478Schristos 		refclock_write(peer, COMMAND_HALT_BCAST, 2,
410*eabc0478Schristos 			       COMMAND_HALT_BCAST);
411abb0f93cSkardel 		return;
412abb0f93cSkardel 	}
413abb0f93cSkardel 	if (syncchar != ' ')
414abb0f93cSkardel 		pp->leap = LEAP_NOTINSYNC;
415abb0f93cSkardel 	else
416abb0f93cSkardel 		pp->leap = LEAP_NOWARNING;
417abb0f93cSkardel 
418abb0f93cSkardel 	/*
419abb0f93cSkardel 	 * Process the new sample in the median filter and determine the
420abb0f93cSkardel 	 * timecode timestamp.
421abb0f93cSkardel 	 */
422abb0f93cSkardel 	if (!refclock_process(pp))
423abb0f93cSkardel 		refclock_report(peer, CEVNT_BADTIME);
424abb0f93cSkardel 	else if (peer->disp > MAXDISTANCE)
425abb0f93cSkardel 		refclock_receive(peer);
426abb0f93cSkardel 
427f003fb54Skardel 	/* if (up->tcswitch >= MAXSTAGE) { */
428*eabc0478Schristos 	refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST);
429f003fb54Skardel 	/* } */
430abb0f93cSkardel }
431abb0f93cSkardel 
432abb0f93cSkardel 
433abb0f93cSkardel /*
434abb0f93cSkardel  * arb_poll - called by the transmit procedure
435abb0f93cSkardel  */
436abb0f93cSkardel static void
437abb0f93cSkardel arb_poll(
438abb0f93cSkardel 	int unit,
439abb0f93cSkardel 	struct peer *peer
440abb0f93cSkardel 	)
441abb0f93cSkardel {
442abb0f93cSkardel 	register struct arbunit *up;
443abb0f93cSkardel 	struct refclockproc *pp;
444abb0f93cSkardel 
445abb0f93cSkardel 	/*
446abb0f93cSkardel 	 * Time to poll the clock. The Arbiter clock responds to a "B5"
447abb0f93cSkardel 	 * by returning a timecode in the format specified above.
448abb0f93cSkardel 	 * Transmission occurs once per second, unless turned off by a
449abb0f93cSkardel 	 * "B0". Note there is no checking on state, since this may not
450abb0f93cSkardel 	 * be the only customer reading the clock. Only one customer
451abb0f93cSkardel 	 * need poll the clock; all others just listen in.
452abb0f93cSkardel 	 */
453abb0f93cSkardel 	pp = peer->procptr;
4548585484eSchristos 	up = pp->unitptr;
455abb0f93cSkardel 	pp->polls++;
456abb0f93cSkardel 	up->tcswitch = 0;
457*eabc0478Schristos 	if (refclock_write(peer, "TQ", 2, "TQ") != 2)
458abb0f93cSkardel 		refclock_report(peer, CEVNT_FAULT);
459abb0f93cSkardel 
460abb0f93cSkardel 	/*
461abb0f93cSkardel 	 * Process median filter samples. If none received, declare a
462abb0f93cSkardel 	 * timeout and keep going.
463abb0f93cSkardel 	 */
464abb0f93cSkardel 	if (pp->coderecv == pp->codeproc) {
465abb0f93cSkardel 		refclock_report(peer, CEVNT_TIMEOUT);
466abb0f93cSkardel 		return;
467abb0f93cSkardel 	}
468abb0f93cSkardel 	refclock_receive(peer);
469abb0f93cSkardel 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
470abb0f93cSkardel #ifdef DEBUG
471abb0f93cSkardel 	if (debug)
472abb0f93cSkardel 		printf("arbiter: timecode %d %s\n",
473abb0f93cSkardel 		   pp->lencode, pp->a_lastcode);
474abb0f93cSkardel #endif
475abb0f93cSkardel }
476abb0f93cSkardel 
477abb0f93cSkardel #else
478*eabc0478Schristos NONEMPTY_TRANSLATION_UNIT
479abb0f93cSkardel #endif /* REFCLOCK */
480