154359Sroberto/*
254359Sroberto * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
354359Sroberto *	Controlled Clock
454359Sroberto */
554359Sroberto
654359Sroberto#ifdef HAVE_CONFIG_H
754359Sroberto#include <config.h>
854359Sroberto#endif
954359Sroberto
1054359Sroberto#if defined(REFCLOCK) && defined(CLOCK_ARBITER)
1154359Sroberto
1254359Sroberto#include "ntpd.h"
1354359Sroberto#include "ntp_io.h"
1454359Sroberto#include "ntp_refclock.h"
1554359Sroberto#include "ntp_stdlib.h"
1654359Sroberto
1782498Sroberto#include <stdio.h>
1882498Sroberto#include <ctype.h>
1982498Sroberto
20285612Sdelphij#ifdef SYS_WINNT
21285612Sdelphijextern int async_write(int, const void *, unsigned int);
22285612Sdelphij#undef write
23285612Sdelphij#define write(fd, data, octets)	async_write(fd, data, octets)
24285612Sdelphij#endif
25285612Sdelphij
2654359Sroberto/*
2754359Sroberto * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
2854359Sroberto * The claimed accuracy of this clock is 100 ns relative to the PPS
2954359Sroberto * output when receiving four or more satellites.
3054359Sroberto *
3154359Sroberto * The receiver should be configured before starting the NTP daemon, in
3254359Sroberto * order to establish reliable position and operating conditions. It
3354359Sroberto * does not initiate surveying or hold mode. For use with NTP, the
3454359Sroberto * daylight savings time feature should be disables (D0 command) and the
3554359Sroberto * broadcast mode set to operate in UTC (BU command).
3654359Sroberto *
3754359Sroberto * The timecode format supported by this driver is selected by the poll
3854359Sroberto * sequence "B5", which initiates a line in the following format to be
3954359Sroberto * repeated once per second until turned off by the "B0" poll sequence.
4054359Sroberto *
4154359Sroberto * Format B5 (24 ASCII printing characters):
4254359Sroberto *
4354359Sroberto * <cr><lf>i yy ddd hh:mm:ss.000bbb
4454359Sroberto *
4554359Sroberto *	on-time = <cr>
4654359Sroberto *	i = synchronization flag (' ' = locked, '?' = unlocked)
4754359Sroberto *	yy = year of century
4854359Sroberto *	ddd = day of year
4954359Sroberto *	hh:mm:ss = hours, minutes, seconds
5054359Sroberto *	.000 = fraction of second (not used)
5154359Sroberto *	bbb = tailing spaces for fill
5254359Sroberto *
5354359Sroberto * The alarm condition is indicated by a '?' at i, which indicates the
5454359Sroberto * receiver is not synchronized. In normal operation, a line consisting
5554359Sroberto * of the timecode followed by the time quality character (TQ) followed
5654359Sroberto * by the receiver status string (SR) is written to the clockstats file.
5754359Sroberto * The time quality character is encoded in IEEE P1344 standard:
5854359Sroberto *
5954359Sroberto * Format TQ (IEEE P1344 estimated worst-case time quality)
6054359Sroberto *
6154359Sroberto *	0	clock locked, maximum accuracy
6254359Sroberto *	F	clock failure, time not reliable
6354359Sroberto *	4	clock unlocked, accuracy < 1 us
6454359Sroberto *	5	clock unlocked, accuracy < 10 us
6554359Sroberto *	6	clock unlocked, accuracy < 100 us
6654359Sroberto *	7	clock unlocked, accuracy < 1 ms
6754359Sroberto *	8	clock unlocked, accuracy < 10 ms
6854359Sroberto *	9	clock unlocked, accuracy < 100 ms
6954359Sroberto *	A	clock unlocked, accuracy < 1 s
7054359Sroberto *	B	clock unlocked, accuracy < 10 s
7154359Sroberto *
7254359Sroberto * The status string is encoded as follows:
7354359Sroberto *
7454359Sroberto * Format SR (25 ASCII printing characters)
7554359Sroberto *
7654359Sroberto *	V=vv S=ss T=t P=pdop E=ee
7754359Sroberto *
7854359Sroberto *	vv = satellites visible
7954359Sroberto *	ss = relative signal strength
8054359Sroberto *	t = satellites tracked
8154359Sroberto *	pdop = position dilution of precision (meters)
8254359Sroberto *	ee = hardware errors
8354359Sroberto *
8454359Sroberto * If flag4 is set, an additional line consisting of the receiver
85182007Sroberto * latitude (LA), longitude (LO), elevation (LH) (meters), and data
86182007Sroberto * buffer (DB) is written to this file. If channel B is enabled for
87182007Sroberto * deviation mode and connected to a 1-PPS signal, the last two numbers
88182007Sroberto * on the line are the deviation and standard deviation averaged over
89182007Sroberto * the last 15 seconds.
90182007Sroberto *
91182007Sroberto * PPS calibration fudge time1 .001240
9254359Sroberto */
9354359Sroberto
9454359Sroberto/*
9554359Sroberto * Interface definitions
9654359Sroberto */
9754359Sroberto#define	DEVICE		"/dev/gps%d" /* device name and unit */
9854359Sroberto#define	SPEED232	B9600	/* uart speed (9600 baud) */
9954359Sroberto#define	PRECISION	(-20)	/* precision assumed (about 1 us) */
100182007Sroberto#define	REFID		"GPS "	/* reference ID */
10154359Sroberto#define	DESCRIPTION	"Arbiter 1088A/B GPS Receiver" /* WRU */
10254359Sroberto#define	LENARB		24	/* format B5 timecode length */
103182007Sroberto#define MAXSTA		40	/* max length of status string */
104182007Sroberto#define MAXPOS		80	/* max length of position string */
10554359Sroberto
106285612Sdelphij#ifdef PRE_NTP420
107285612Sdelphij#define MODE ttlmax
108285612Sdelphij#else
109285612Sdelphij#define MODE ttl
110285612Sdelphij#endif
111285612Sdelphij
112285612Sdelphij#define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
113285612Sdelphij#define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
114285612Sdelphij
11554359Sroberto/*
11654359Sroberto * ARB unit control structure
11754359Sroberto */
11854359Srobertostruct arbunit {
11954359Sroberto	l_fp	laststamp;	/* last receive timestamp */
12054359Sroberto	int	tcswitch;	/* timecode switch/counter */
12154359Sroberto	char	qualchar;	/* IEEE P1344 quality (TQ command) */
12254359Sroberto	char	status[MAXSTA];	/* receiver status (SR command) */
12354359Sroberto	char	latlon[MAXPOS];	/* receiver position (lat/lon/alt) */
12454359Sroberto};
12554359Sroberto
12654359Sroberto/*
12754359Sroberto * Function prototypes
12854359Sroberto */
129285612Sdelphijstatic	int	arb_start	(int, struct peer *);
130285612Sdelphijstatic	void	arb_shutdown	(int, struct peer *);
131285612Sdelphijstatic	void	arb_receive	(struct recvbuf *);
132285612Sdelphijstatic	void	arb_poll	(int, struct peer *);
13354359Sroberto
13454359Sroberto/*
13554359Sroberto * Transfer vector
13654359Sroberto */
13754359Srobertostruct	refclock refclock_arbiter = {
13854359Sroberto	arb_start,		/* start up driver */
13954359Sroberto	arb_shutdown,		/* shut down driver */
14054359Sroberto	arb_poll,		/* transmit poll message */
14154359Sroberto	noentry,		/* not used (old arb_control) */
14254359Sroberto	noentry,		/* initialize driver (not used) */
14354359Sroberto	noentry,		/* not used (old arb_buginfo) */
14454359Sroberto	NOFLAGS			/* not used */
14554359Sroberto};
14654359Sroberto
14754359Sroberto
14854359Sroberto/*
14954359Sroberto * arb_start - open the devices and initialize data for processing
15054359Sroberto */
15154359Srobertostatic int
15254359Srobertoarb_start(
15354359Sroberto	int unit,
15454359Sroberto	struct peer *peer
15554359Sroberto	)
15654359Sroberto{
15754359Sroberto	register struct arbunit *up;
15854359Sroberto	struct refclockproc *pp;
15954359Sroberto	int fd;
16054359Sroberto	char device[20];
16154359Sroberto
16254359Sroberto	/*
16354359Sroberto	 * Open serial port. Use CLK line discipline, if available.
16454359Sroberto	 */
165285612Sdelphij	snprintf(device, sizeof(device), DEVICE, unit);
166285612Sdelphij	fd = refclock_open(device, SPEED232, LDISC_CLK);
167285612Sdelphij	if (fd <= 0)
16854359Sroberto		return (0);
16954359Sroberto
17054359Sroberto	/*
17154359Sroberto	 * Allocate and initialize unit structure
17254359Sroberto	 */
173285612Sdelphij	up = emalloc_zero(sizeof(*up));
17454359Sroberto	pp = peer->procptr;
17554359Sroberto	pp->io.clock_recv = arb_receive;
176285612Sdelphij	pp->io.srcclock = peer;
17754359Sroberto	pp->io.datalen = 0;
17854359Sroberto	pp->io.fd = fd;
17954359Sroberto	if (!io_addclock(&pp->io)) {
180285612Sdelphij		close(fd);
181285612Sdelphij		pp->io.fd = -1;
18254359Sroberto		free(up);
18354359Sroberto		return (0);
18454359Sroberto	}
185285612Sdelphij	pp->unitptr = up;
18654359Sroberto
18754359Sroberto	/*
18854359Sroberto	 * Initialize miscellaneous variables
18954359Sroberto	 */
19054359Sroberto	peer->precision = PRECISION;
19154359Sroberto	pp->clockdesc = DESCRIPTION;
19254359Sroberto	memcpy((char *)&pp->refid, REFID, 4);
193285612Sdelphij	if (peer->MODE > 1) {
194285612Sdelphij		msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
195285612Sdelphij		close(fd);
196285612Sdelphij		pp->io.fd = -1;
197285612Sdelphij		free(up);
198285612Sdelphij		return (0);
199285612Sdelphij	}
200285612Sdelphij#ifdef DEBUG
201285612Sdelphij	if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
202285612Sdelphij#endif
203285612Sdelphij	write(pp->io.fd, COMMAND_HALT_BCAST, 2);
20454359Sroberto	return (1);
20554359Sroberto}
20654359Sroberto
20754359Sroberto
20854359Sroberto/*
20954359Sroberto * arb_shutdown - shut down the clock
21054359Sroberto */
21154359Srobertostatic void
21254359Srobertoarb_shutdown(
21354359Sroberto	int unit,
21454359Sroberto	struct peer *peer
21554359Sroberto	)
21654359Sroberto{
21754359Sroberto	register struct arbunit *up;
21854359Sroberto	struct refclockproc *pp;
21954359Sroberto
22054359Sroberto	pp = peer->procptr;
221285612Sdelphij	up = pp->unitptr;
222285612Sdelphij	if (-1 != pp->io.fd)
223285612Sdelphij		io_closeclock(&pp->io);
224285612Sdelphij	if (NULL != up)
225285612Sdelphij		free(up);
22654359Sroberto}
22754359Sroberto
22854359Sroberto
22954359Sroberto/*
23054359Sroberto * arb_receive - receive data from the serial interface
23154359Sroberto */
23254359Srobertostatic void
23354359Srobertoarb_receive(
23454359Sroberto	struct recvbuf *rbufp
23554359Sroberto	)
23654359Sroberto{
23754359Sroberto	register struct arbunit *up;
23854359Sroberto	struct refclockproc *pp;
23954359Sroberto	struct peer *peer;
24054359Sroberto	l_fp trtmp;
24154359Sroberto	int temp;
242182007Sroberto	u_char	syncchar;		/* synch indicator */
243182007Sroberto	char	tbuf[BMAX];		/* temp buffer */
24454359Sroberto
24554359Sroberto	/*
24654359Sroberto	 * Initialize pointers and read the timecode and timestamp
24754359Sroberto	 */
248285612Sdelphij	peer = rbufp->recv_peer;
24954359Sroberto	pp = peer->procptr;
250285612Sdelphij	up = pp->unitptr;
251285612Sdelphij	temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp);
25254359Sroberto
25354359Sroberto	/*
25454359Sroberto	 * Note we get a buffer and timestamp for both a <cr> and <lf>,
25554359Sroberto	 * but only the <cr> timestamp is retained. The program first
25654359Sroberto	 * sends a TQ and expects the echo followed by the time quality
25754359Sroberto	 * character. It then sends a B5 starting the timecode broadcast
25854359Sroberto	 * and expects the echo followed some time later by the on-time
25954359Sroberto	 * character <cr> and then the <lf> beginning the timecode
26054359Sroberto	 * itself. Finally, at the <cr> beginning the next timecode at
26154359Sroberto	 * the next second, the program sends a B0 shutting down the
26254359Sroberto	 * timecode broadcast.
26354359Sroberto	 *
26454359Sroberto	 * If flag4 is set, the program snatches the latitude, longitude
26554359Sroberto	 * and elevation and writes it to the clockstats file.
26654359Sroberto	 */
26754359Sroberto	if (temp == 0)
26854359Sroberto		return;
269182007Sroberto
27054359Sroberto	pp->lastrec = up->laststamp;
27154359Sroberto	up->laststamp = trtmp;
27254359Sroberto	if (temp < 3)
27354359Sroberto		return;
274182007Sroberto
27554359Sroberto	if (up->tcswitch == 0) {
27654359Sroberto
27754359Sroberto		/*
27854359Sroberto		 * Collect statistics. If nothing is recogized, just
27954359Sroberto		 * ignore; sometimes the clock doesn't stop spewing
280182007Sroberto		 * timecodes for awhile after the B0 command.
281182007Sroberto		 *
282182007Sroberto		 * If flag4 is not set, send TQ, SR, B5. If flag4 is
283182007Sroberto		 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
284182007Sroberto		 * median filter is full, send B0.
28554359Sroberto		 */
286182007Sroberto		if (!strncmp(tbuf, "TQ", 2)) {
287182007Sroberto			up->qualchar = tbuf[2];
28854359Sroberto			write(pp->io.fd, "SR", 2);
289182007Sroberto			return;
290182007Sroberto
291182007Sroberto		} else if (!strncmp(tbuf, "SR", 2)) {
292285612Sdelphij			strlcpy(up->status, tbuf + 2,
293285612Sdelphij				sizeof(up->status));
29454359Sroberto			if (pp->sloppyclockflag & CLK_FLAG4)
29554359Sroberto				write(pp->io.fd, "LA", 2);
296182007Sroberto			else
297285612Sdelphij				write(pp->io.fd, COMMAND_START_BCAST, 2);
298182007Sroberto			return;
299182007Sroberto
300182007Sroberto		} else if (!strncmp(tbuf, "LA", 2)) {
301285612Sdelphij			strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon));
30254359Sroberto			write(pp->io.fd, "LO", 2);
303182007Sroberto			return;
304182007Sroberto
305182007Sroberto		} else if (!strncmp(tbuf, "LO", 2)) {
306285612Sdelphij			strlcat(up->latlon, " ", sizeof(up->latlon));
307285612Sdelphij			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
30854359Sroberto			write(pp->io.fd, "LH", 2);
309182007Sroberto			return;
310182007Sroberto
311182007Sroberto		} else if (!strncmp(tbuf, "LH", 2)) {
312285612Sdelphij			strlcat(up->latlon, " ", sizeof(up->latlon));
313285612Sdelphij			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
31454359Sroberto			write(pp->io.fd, "DB", 2);
315182007Sroberto			return;
316182007Sroberto
317182007Sroberto		} else if (!strncmp(tbuf, "DB", 2)) {
318285612Sdelphij			strlcat(up->latlon, " ", sizeof(up->latlon));
319285612Sdelphij			strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
32054359Sroberto			record_clock_stats(&peer->srcadr, up->latlon);
321182007Sroberto#ifdef DEBUG
322182007Sroberto			if (debug)
323182007Sroberto				printf("arbiter: %s\n", up->latlon);
324182007Sroberto#endif
325285612Sdelphij			write(pp->io.fd, COMMAND_START_BCAST, 2);
32654359Sroberto		}
32754359Sroberto	}
32854359Sroberto
32954359Sroberto	/*
33054359Sroberto	 * We get down to business, check the timecode format and decode
33154359Sroberto	 * its contents. If the timecode has valid length, but not in
33254359Sroberto	 * proper format, we declare bad format and exit. If the
33354359Sroberto	 * timecode has invalid length, which sometimes occurs when the
33454359Sroberto	 * B0 amputates the broadcast, we just quietly steal away. Note
33554359Sroberto	 * that the time quality character and receiver status string is
33654359Sroberto	 * tacked on the end for clockstats display.
33754359Sroberto	 */
338182007Sroberto	up->tcswitch++;
339182007Sroberto	if (up->tcswitch <= 1 || temp < LENARB)
340182007Sroberto		return;
341182007Sroberto
342182007Sroberto	/*
343182007Sroberto	 * Timecode format B5: "i yy ddd hh:mm:ss.000   "
344182007Sroberto	 */
345285612Sdelphij	strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode));
346182007Sroberto	pp->a_lastcode[LENARB - 2] = up->qualchar;
347285612Sdelphij	strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode));
348182007Sroberto	pp->lencode = strlen(pp->a_lastcode);
349182007Sroberto	syncchar = ' ';
350182007Sroberto	if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
351182007Sroberto	    &syncchar, &pp->year, &pp->day, &pp->hour,
352182007Sroberto	    &pp->minute, &pp->second) != 6) {
353182007Sroberto		refclock_report(peer, CEVNT_BADREPLY);
354285612Sdelphij		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
35554359Sroberto		return;
35654359Sroberto	}
35754359Sroberto
35854359Sroberto	/*
35954359Sroberto	 * We decode the clock dispersion from the time quality
36054359Sroberto	 * character.
36154359Sroberto	 */
36254359Sroberto	switch (up->qualchar) {
36354359Sroberto
36454359Sroberto	    case '0':		/* locked, max accuracy */
36554359Sroberto		pp->disp = 1e-7;
366182007Sroberto		pp->lastref = pp->lastrec;
36754359Sroberto		break;
36854359Sroberto
36954359Sroberto	    case '4':		/* unlock accuracy < 1 us */
37054359Sroberto		pp->disp = 1e-6;
37154359Sroberto		break;
37254359Sroberto
37354359Sroberto	    case '5':		/* unlock accuracy < 10 us */
37454359Sroberto		pp->disp = 1e-5;
37554359Sroberto		break;
37654359Sroberto
37754359Sroberto	    case '6':		/* unlock accuracy < 100 us */
37854359Sroberto		pp->disp = 1e-4;
37954359Sroberto		break;
38054359Sroberto
38154359Sroberto	    case '7':		/* unlock accuracy < 1 ms */
38254359Sroberto		pp->disp = .001;
38354359Sroberto		break;
38454359Sroberto
38554359Sroberto	    case '8':		/* unlock accuracy < 10 ms */
38654359Sroberto		pp->disp = .01;
38754359Sroberto		break;
38854359Sroberto
38954359Sroberto	    case '9':		/* unlock accuracy < 100 ms */
39054359Sroberto		pp->disp = .1;
39154359Sroberto		break;
39254359Sroberto
39354359Sroberto	    case 'A':		/* unlock accuracy < 1 s */
39454359Sroberto		pp->disp = 1;
39554359Sroberto		break;
39654359Sroberto
39754359Sroberto	    case 'B':		/* unlock accuracy < 10 s */
39854359Sroberto		pp->disp = 10;
39954359Sroberto		break;
40054359Sroberto
40154359Sroberto	    case 'F':		/* clock failure */
40254359Sroberto		pp->disp = MAXDISPERSE;
40354359Sroberto		refclock_report(peer, CEVNT_FAULT);
404285612Sdelphij		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
40554359Sroberto		return;
40654359Sroberto
40754359Sroberto	    default:
40854359Sroberto		pp->disp = MAXDISPERSE;
40954359Sroberto		refclock_report(peer, CEVNT_BADREPLY);
410285612Sdelphij		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
41154359Sroberto		return;
41254359Sroberto	}
41354359Sroberto	if (syncchar != ' ')
41454359Sroberto		pp->leap = LEAP_NOTINSYNC;
41554359Sroberto	else
41654359Sroberto		pp->leap = LEAP_NOWARNING;
41754359Sroberto
41854359Sroberto	/*
41954359Sroberto	 * Process the new sample in the median filter and determine the
42054359Sroberto	 * timecode timestamp.
42154359Sroberto	 */
42254359Sroberto	if (!refclock_process(pp))
42354359Sroberto		refclock_report(peer, CEVNT_BADTIME);
424182007Sroberto	else if (peer->disp > MAXDISTANCE)
425182007Sroberto		refclock_receive(peer);
426182007Sroberto
427285612Sdelphij	/* if (up->tcswitch >= MAXSTAGE) { */
428285612Sdelphij	write(pp->io.fd, COMMAND_HALT_BCAST, 2);
429285612Sdelphij	/* } */
43054359Sroberto}
43154359Sroberto
43254359Sroberto
43354359Sroberto/*
43454359Sroberto * arb_poll - called by the transmit procedure
43554359Sroberto */
43654359Srobertostatic void
43754359Srobertoarb_poll(
43854359Sroberto	int unit,
43954359Sroberto	struct peer *peer
44054359Sroberto	)
44154359Sroberto{
44254359Sroberto	register struct arbunit *up;
44354359Sroberto	struct refclockproc *pp;
44454359Sroberto
44554359Sroberto	/*
44654359Sroberto	 * Time to poll the clock. The Arbiter clock responds to a "B5"
44754359Sroberto	 * by returning a timecode in the format specified above.
44854359Sroberto	 * Transmission occurs once per second, unless turned off by a
44954359Sroberto	 * "B0". Note there is no checking on state, since this may not
45054359Sroberto	 * be the only customer reading the clock. Only one customer
451182007Sroberto	 * need poll the clock; all others just listen in.
45254359Sroberto	 */
45354359Sroberto	pp = peer->procptr;
454285612Sdelphij	up = pp->unitptr;
455182007Sroberto	pp->polls++;
45654359Sroberto	up->tcswitch = 0;
457182007Sroberto	if (write(pp->io.fd, "TQ", 2) != 2)
45854359Sroberto		refclock_report(peer, CEVNT_FAULT);
459182007Sroberto
460182007Sroberto	/*
461182007Sroberto	 * Process median filter samples. If none received, declare a
462182007Sroberto	 * timeout and keep going.
463182007Sroberto	 */
46454359Sroberto	if (pp->coderecv == pp->codeproc) {
46554359Sroberto		refclock_report(peer, CEVNT_TIMEOUT);
46654359Sroberto		return;
46754359Sroberto	}
468132451Sroberto	refclock_receive(peer);
46954359Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
470182007Sroberto#ifdef DEBUG
471182007Sroberto	if (debug)
472182007Sroberto		printf("arbiter: timecode %d %s\n",
473182007Sroberto		   pp->lencode, pp->a_lastcode);
474182007Sroberto#endif
47554359Sroberto}
47654359Sroberto
47754359Sroberto#else
47854359Srobertoint refclock_arbiter_bs;
47954359Sroberto#endif /* REFCLOCK */
480