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