refclock_tpro.c revision 82498
154359Sroberto/*
254359Sroberto * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader
354359Sroberto */
454359Sroberto
554359Sroberto#ifdef HAVE_CONFIG_H
654359Sroberto#include <config.h>
754359Sroberto#endif
854359Sroberto
954359Sroberto#if defined(REFCLOCK) && defined(CLOCK_TPRO)
1054359Sroberto
1154359Sroberto#include "ntpd.h"
1254359Sroberto#include "ntp_io.h"
1354359Sroberto#include "ntp_refclock.h"
1454359Sroberto#include "ntp_unixtime.h"
1554359Sroberto#include "sys/tpro.h"
1654359Sroberto#include "ntp_stdlib.h"
1754359Sroberto
1882498Sroberto#include <stdio.h>
1982498Sroberto#include <ctype.h>
2082498Sroberto
2154359Sroberto/*
2254359Sroberto * This driver supports the KSI/Odetecs TPRO-S IRIG-B reader and TPRO-
2354359Sroberto * SAT GPS receiver for the Sun Microsystems SBus. It requires that the
2454359Sroberto * tpro.o device driver be installed and loaded.
2554359Sroberto */
2654359Sroberto
2754359Sroberto/*
2854359Sroberto * TPRO interface definitions
2954359Sroberto */
3054359Sroberto#define	DEVICE		 "/dev/tpro%d" /* device name and unit */
3154359Sroberto#define	PRECISION	(-20)	/* precision assumed (1 us) */
3254359Sroberto#define	REFID		"IRIG"	/* reference ID */
3354359Sroberto#define	DESCRIPTION	"KSI/Odetics TPRO/S IRIG Interface" /* WRU */
3454359Sroberto
3554359Sroberto/*
3654359Sroberto * Unit control structure
3754359Sroberto */
3854359Srobertostruct tprounit {
3954359Sroberto	struct	tproval tprodata; /* data returned from tpro read */
4054359Sroberto};
4154359Sroberto
4254359Sroberto/*
4354359Sroberto * Function prototypes
4454359Sroberto */
4554359Srobertostatic	int	tpro_start	P((int, struct peer *));
4654359Srobertostatic	void	tpro_shutdown	P((int, struct peer *));
4754359Srobertostatic	void	tpro_poll	P((int unit, struct peer *));
4854359Sroberto
4954359Sroberto/*
5054359Sroberto * Transfer vector
5154359Sroberto */
5254359Srobertostruct	refclock refclock_tpro = {
5354359Sroberto	tpro_start,		/* start up driver */
5454359Sroberto	tpro_shutdown,		/* shut down driver */
5554359Sroberto	tpro_poll,		/* transmit poll message */
5654359Sroberto	noentry,		/* not used (old tpro_control) */
5754359Sroberto	noentry,		/* initialize driver (not used) */
5854359Sroberto	noentry,		/* not used (old tpro_buginfo) */
5954359Sroberto	NOFLAGS			/* not used */
6054359Sroberto};
6154359Sroberto
6254359Sroberto
6354359Sroberto/*
6454359Sroberto * tpro_start - open the TPRO device and initialize data for processing
6554359Sroberto */
6654359Srobertostatic int
6754359Srobertotpro_start(
6854359Sroberto	int unit,
6954359Sroberto	struct peer *peer
7054359Sroberto	)
7154359Sroberto{
7254359Sroberto	register struct tprounit *up;
7354359Sroberto	struct refclockproc *pp;
7454359Sroberto	char device[20];
7554359Sroberto	int fd;
7654359Sroberto
7754359Sroberto	/*
7854359Sroberto	 * Open TPRO device
7954359Sroberto	 */
8054359Sroberto	(void)sprintf(device, DEVICE, unit);
8154359Sroberto	fd = open(device, O_RDONLY | O_NDELAY, 0777);
8254359Sroberto	if (fd == -1) {
8354359Sroberto		msyslog(LOG_ERR, "tpro_start: open of %s: %m", device);
8454359Sroberto		return (0);
8554359Sroberto	}
8654359Sroberto
8754359Sroberto	/*
8854359Sroberto	 * Allocate and initialize unit structure
8954359Sroberto	 */
9054359Sroberto	if (!(up = (struct tprounit *) emalloc(sizeof(struct tprounit)))) {
9154359Sroberto		(void) close(fd);
9254359Sroberto		return (0);
9354359Sroberto	}
9454359Sroberto	memset((char *)up, 0, sizeof(struct tprounit));
9554359Sroberto	pp = peer->procptr;
9654359Sroberto	pp->io.clock_recv = noentry;
9754359Sroberto	pp->io.srcclock = (caddr_t)peer;
9854359Sroberto	pp->io.datalen = 0;
9954359Sroberto	pp->io.fd = fd;
10054359Sroberto	pp->unitptr = (caddr_t)up;
10154359Sroberto
10254359Sroberto	/*
10354359Sroberto	 * Initialize miscellaneous peer variables
10454359Sroberto	 */
10554359Sroberto	peer->precision = PRECISION;
10654359Sroberto	peer->burst = NSTAGE;
10754359Sroberto	pp->clockdesc = DESCRIPTION;
10854359Sroberto	memcpy((char *)&pp->refid, REFID, 4);
10954359Sroberto	return (1);
11054359Sroberto}
11154359Sroberto
11254359Sroberto
11354359Sroberto/*
11454359Sroberto * tpro_shutdown - shut down the clock
11554359Sroberto */
11654359Srobertostatic void
11754359Srobertotpro_shutdown(
11854359Sroberto	int unit,
11954359Sroberto	struct peer *peer
12054359Sroberto	)
12154359Sroberto{
12254359Sroberto	register struct tprounit *up;
12354359Sroberto	struct refclockproc *pp;
12454359Sroberto
12554359Sroberto	pp = peer->procptr;
12654359Sroberto	up = (struct tprounit *)pp->unitptr;
12754359Sroberto	io_closeclock(&pp->io);
12854359Sroberto	free(up);
12954359Sroberto}
13054359Sroberto
13154359Sroberto
13254359Sroberto/*
13354359Sroberto * tpro_poll - called by the transmit procedure
13454359Sroberto */
13554359Srobertostatic void
13654359Srobertotpro_poll(
13754359Sroberto	int unit,
13854359Sroberto	struct peer *peer
13954359Sroberto	)
14054359Sroberto{
14154359Sroberto	register struct tprounit *up;
14254359Sroberto	struct refclockproc *pp;
14354359Sroberto	struct tproval *tp;
14454359Sroberto
14554359Sroberto	/*
14654359Sroberto	 * This is the main routine. It snatches the time from the TPRO
14754359Sroberto	 * board and tacks on a local timestamp.
14854359Sroberto	 */
14954359Sroberto	pp = peer->procptr;
15054359Sroberto	up = (struct tprounit *)pp->unitptr;
15154359Sroberto
15254359Sroberto	tp = &up->tprodata;
15354359Sroberto	if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) {
15454359Sroberto		refclock_report(peer, CEVNT_FAULT);
15554359Sroberto		return;
15654359Sroberto	}
15754359Sroberto	get_systime(&pp->lastrec);
15854359Sroberto	pp->polls++;
15954359Sroberto
16054359Sroberto	/*
16154359Sroberto	 * We get down to business, check the timecode format and decode
16254359Sroberto	 * its contents. If the timecode has invalid length or is not in
16354359Sroberto	 * proper format, we declare bad format and exit. Note: we
16454359Sroberto	 * can't use the sec/usec conversion produced by the driver,
16554359Sroberto	 * since the year may be suspect. All format error checking is
16654359Sroberto	 * done by the sprintf() and sscanf() routines.
16754359Sroberto	 */
16854359Sroberto	sprintf(pp->a_lastcode,
16954359Sroberto	    "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
17054359Sroberto	    tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
17154359Sroberto	    tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
17254359Sroberto	    tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
17354359Sroberto	    tp->status);
17454359Sroberto	    pp->lencode = strlen(pp->a_lastcode);
17554359Sroberto#ifdef DEBUG
17654359Sroberto	if (debug)
17754359Sroberto		printf("tpro: time %s timecode %d %s\n",
17854359Sroberto		   ulfptoa(&pp->lastrec, 6), pp->lencode,
17954359Sroberto		   pp->a_lastcode);
18054359Sroberto#endif
18154359Sroberto	if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day,
18254359Sroberto	    &pp->hour, &pp->minute, &pp->second, &pp->usec)
18354359Sroberto	    != 5) {
18454359Sroberto		refclock_report(peer, CEVNT_BADTIME);
18554359Sroberto		return;
18654359Sroberto	}
18754359Sroberto	if (!tp->status & 0x3)
18854359Sroberto		pp->leap = LEAP_NOTINSYNC;
18954359Sroberto	else
19054359Sroberto		pp->leap = LEAP_NOWARNING;
19154359Sroberto	if (!refclock_process(pp)) {
19254359Sroberto		refclock_report(peer, CEVNT_BADTIME);
19354359Sroberto		return;
19454359Sroberto	}
19554359Sroberto	if (peer->burst > 0)
19654359Sroberto		return;
19754359Sroberto	if (pp->coderecv == pp->codeproc) {
19854359Sroberto		refclock_report(peer, CEVNT_TIMEOUT);
19954359Sroberto		return;
20054359Sroberto	}
20154359Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
20254359Sroberto	refclock_receive(peer);
20354359Sroberto	peer->burst = NSTAGE;
20454359Sroberto}
20554359Sroberto
20654359Sroberto#else
20754359Srobertoint refclock_tpro_bs;
20854359Sroberto#endif /* REFCLOCK */
209