1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader
3c0b746e5SOllivier Robert */
4c0b746e5SOllivier Robert
5c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
6c0b746e5SOllivier Robert #include <config.h>
7c0b746e5SOllivier Robert #endif
8c0b746e5SOllivier Robert
9c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_TPRO)
10c0b746e5SOllivier Robert
11c0b746e5SOllivier Robert #include "ntpd.h"
12c0b746e5SOllivier Robert #include "ntp_io.h"
13c0b746e5SOllivier Robert #include "ntp_refclock.h"
14c0b746e5SOllivier Robert #include "ntp_unixtime.h"
15c0b746e5SOllivier Robert #include "sys/tpro.h"
16c0b746e5SOllivier Robert #include "ntp_stdlib.h"
17c0b746e5SOllivier Robert
18224ba2bdSOllivier Robert #include <stdio.h>
19224ba2bdSOllivier Robert #include <ctype.h>
20224ba2bdSOllivier Robert
21c0b746e5SOllivier Robert /*
22c0b746e5SOllivier Robert * This driver supports the KSI/Odetecs TPRO-S IRIG-B reader and TPRO-
23c0b746e5SOllivier Robert * SAT GPS receiver for the Sun Microsystems SBus. It requires that the
24c0b746e5SOllivier Robert * tpro.o device driver be installed and loaded.
25c0b746e5SOllivier Robert */
26c0b746e5SOllivier Robert
27c0b746e5SOllivier Robert /*
28c0b746e5SOllivier Robert * TPRO interface definitions
29c0b746e5SOllivier Robert */
30c0b746e5SOllivier Robert #define DEVICE "/dev/tpro%d" /* device name and unit */
31c0b746e5SOllivier Robert #define PRECISION (-20) /* precision assumed (1 us) */
32c0b746e5SOllivier Robert #define REFID "IRIG" /* reference ID */
33c0b746e5SOllivier Robert #define DESCRIPTION "KSI/Odetics TPRO/S IRIG Interface" /* WRU */
34c0b746e5SOllivier Robert
35c0b746e5SOllivier Robert /*
36c0b746e5SOllivier Robert * Unit control structure
37c0b746e5SOllivier Robert */
38c0b746e5SOllivier Robert struct tprounit {
39c0b746e5SOllivier Robert struct tproval tprodata; /* data returned from tpro read */
40c0b746e5SOllivier Robert };
41c0b746e5SOllivier Robert
42c0b746e5SOllivier Robert /*
43c0b746e5SOllivier Robert * Function prototypes
44c0b746e5SOllivier Robert */
45c0b746e5SOllivier Robert static int tpro_start (int, struct peer *);
46c0b746e5SOllivier Robert static void tpro_shutdown (int, struct peer *);
47c0b746e5SOllivier Robert static void tpro_poll (int unit, struct peer *);
48c0b746e5SOllivier Robert
49c0b746e5SOllivier Robert /*
50c0b746e5SOllivier Robert * Transfer vector
51c0b746e5SOllivier Robert */
52c0b746e5SOllivier Robert struct refclock refclock_tpro = {
53c0b746e5SOllivier Robert tpro_start, /* start up driver */
54c0b746e5SOllivier Robert tpro_shutdown, /* shut down driver */
55c0b746e5SOllivier Robert tpro_poll, /* transmit poll message */
56c0b746e5SOllivier Robert noentry, /* not used (old tpro_control) */
57c0b746e5SOllivier Robert noentry, /* initialize driver (not used) */
58c0b746e5SOllivier Robert noentry, /* not used (old tpro_buginfo) */
59c0b746e5SOllivier Robert NOFLAGS /* not used */
60c0b746e5SOllivier Robert };
61c0b746e5SOllivier Robert
62c0b746e5SOllivier Robert
63c0b746e5SOllivier Robert /*
64c0b746e5SOllivier Robert * tpro_start - open the TPRO device and initialize data for processing
65c0b746e5SOllivier Robert */
66c0b746e5SOllivier Robert static int
tpro_start(int unit,struct peer * peer)67c0b746e5SOllivier Robert tpro_start(
68c0b746e5SOllivier Robert int unit,
69c0b746e5SOllivier Robert struct peer *peer
70c0b746e5SOllivier Robert )
71c0b746e5SOllivier Robert {
72c0b746e5SOllivier Robert register struct tprounit *up;
73c0b746e5SOllivier Robert struct refclockproc *pp;
74c0b746e5SOllivier Robert char device[20];
75c0b746e5SOllivier Robert int fd;
76c0b746e5SOllivier Robert
77c0b746e5SOllivier Robert /*
78c0b746e5SOllivier Robert * Open TPRO device
79c0b746e5SOllivier Robert */
80c0b746e5SOllivier Robert snprintf(device, sizeof(device), DEVICE, unit);
81c0b746e5SOllivier Robert fd = open(device, O_RDONLY | O_NDELAY, 0777);
82c0b746e5SOllivier Robert if (fd == -1) {
83c0b746e5SOllivier Robert msyslog(LOG_ERR, "tpro_start: open of %s: %m", device);
84c0b746e5SOllivier Robert return (0);
85c0b746e5SOllivier Robert }
86c0b746e5SOllivier Robert
87c0b746e5SOllivier Robert /*
88c0b746e5SOllivier Robert * Allocate and initialize unit structure
89c0b746e5SOllivier Robert */
90c0b746e5SOllivier Robert up = emalloc_zero(sizeof(*up));
91c0b746e5SOllivier Robert pp = peer->procptr;
92c0b746e5SOllivier Robert pp->io.clock_recv = noentry;
93c0b746e5SOllivier Robert pp->io.srcclock = peer;
94c0b746e5SOllivier Robert pp->io.datalen = 0;
95c0b746e5SOllivier Robert pp->io.fd = fd;
96c0b746e5SOllivier Robert pp->unitptr = up;
97c0b746e5SOllivier Robert
98c0b746e5SOllivier Robert /*
99c0b746e5SOllivier Robert * Initialize miscellaneous peer variables
100c0b746e5SOllivier Robert */
101c0b746e5SOllivier Robert peer->precision = PRECISION;
102c0b746e5SOllivier Robert pp->clockdesc = DESCRIPTION;
103c0b746e5SOllivier Robert memcpy((char *)&pp->refid, REFID, 4);
104c0b746e5SOllivier Robert return (1);
105c0b746e5SOllivier Robert }
106c0b746e5SOllivier Robert
107c0b746e5SOllivier Robert
108c0b746e5SOllivier Robert /*
109c0b746e5SOllivier Robert * tpro_shutdown - shut down the clock
110c0b746e5SOllivier Robert */
111c0b746e5SOllivier Robert static void
tpro_shutdown(int unit,struct peer * peer)112c0b746e5SOllivier Robert tpro_shutdown(
113c0b746e5SOllivier Robert int unit,
114c0b746e5SOllivier Robert struct peer *peer
115c0b746e5SOllivier Robert )
116c0b746e5SOllivier Robert {
117c0b746e5SOllivier Robert register struct tprounit *up;
118c0b746e5SOllivier Robert struct refclockproc *pp;
119c0b746e5SOllivier Robert
120c0b746e5SOllivier Robert pp = peer->procptr;
121c0b746e5SOllivier Robert up = pp->unitptr;
122c0b746e5SOllivier Robert io_closeclock(&pp->io);
123c0b746e5SOllivier Robert if (NULL != up)
124c0b746e5SOllivier Robert free(up);
125c0b746e5SOllivier Robert }
126c0b746e5SOllivier Robert
127c0b746e5SOllivier Robert
128c0b746e5SOllivier Robert /*
129c0b746e5SOllivier Robert * tpro_poll - called by the transmit procedure
130c0b746e5SOllivier Robert */
131c0b746e5SOllivier Robert static void
tpro_poll(int unit,struct peer * peer)132c0b746e5SOllivier Robert tpro_poll(
133c0b746e5SOllivier Robert int unit,
134c0b746e5SOllivier Robert struct peer *peer
135c0b746e5SOllivier Robert )
136c0b746e5SOllivier Robert {
137c0b746e5SOllivier Robert register struct tprounit *up;
138c0b746e5SOllivier Robert struct refclockproc *pp;
139c0b746e5SOllivier Robert struct tproval *tp;
140c0b746e5SOllivier Robert
141c0b746e5SOllivier Robert /*
142c0b746e5SOllivier Robert * This is the main routine. It snatches the time from the TPRO
143c0b746e5SOllivier Robert * board and tacks on a local timestamp.
144c0b746e5SOllivier Robert */
145c0b746e5SOllivier Robert pp = peer->procptr;
146c0b746e5SOllivier Robert up = pp->unitptr;
147c0b746e5SOllivier Robert
148c0b746e5SOllivier Robert tp = &up->tprodata;
149c0b746e5SOllivier Robert if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) {
150c0b746e5SOllivier Robert refclock_report(peer, CEVNT_FAULT);
151c0b746e5SOllivier Robert return;
152c0b746e5SOllivier Robert }
153c0b746e5SOllivier Robert get_systime(&pp->lastrec);
154c0b746e5SOllivier Robert pp->polls++;
155c0b746e5SOllivier Robert
156c0b746e5SOllivier Robert /*
157c0b746e5SOllivier Robert * We get down to business, check the timecode format and decode
158c0b746e5SOllivier Robert * its contents. If the timecode has invalid length or is not in
159c0b746e5SOllivier Robert * proper format, we declare bad format and exit. Note: we
160c0b746e5SOllivier Robert * can't use the sec/usec conversion produced by the driver,
161c0b746e5SOllivier Robert * since the year may be suspect. All format error checking is
162c0b746e5SOllivier Robert * done by the snprintf() and sscanf() routines.
163c0b746e5SOllivier Robert *
164c0b746e5SOllivier Robert * Note that the refclockproc usec member has now become nsec.
165c0b746e5SOllivier Robert * We could either multiply the read-in usec value by 1000 or
166c0b746e5SOllivier Robert * we could pad the written string appropriately and read the
1679c2daa00SOllivier Robert * resulting value in already scaled.
1689c2daa00SOllivier Robert */
1699c2daa00SOllivier Robert snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
1709c2daa00SOllivier Robert "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
1719c2daa00SOllivier Robert tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
172c0b746e5SOllivier Robert tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
173c0b746e5SOllivier Robert tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
174c0b746e5SOllivier Robert tp->status);
175c0b746e5SOllivier Robert pp->lencode = strlen(pp->a_lastcode);
176c0b746e5SOllivier Robert #ifdef DEBUG
177c0b746e5SOllivier Robert if (debug)
178c0b746e5SOllivier Robert printf("tpro: time %s timecode %d %s\n",
179c0b746e5SOllivier Robert ulfptoa(&pp->lastrec, 6), pp->lencode,
180c0b746e5SOllivier Robert pp->a_lastcode);
181c0b746e5SOllivier Robert #endif
182c0b746e5SOllivier Robert if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day,
183c0b746e5SOllivier Robert &pp->hour, &pp->minute, &pp->second, &pp->nsec)
184c0b746e5SOllivier Robert != 5) {
185c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADTIME);
186c0b746e5SOllivier Robert return;
1879c2daa00SOllivier Robert }
188c0b746e5SOllivier Robert pp->nsec *= 1000; /* Convert usec to nsec */
189c0b746e5SOllivier Robert if (!tp->status & 0x3)
190c0b746e5SOllivier Robert pp->leap = LEAP_NOTINSYNC;
191c0b746e5SOllivier Robert else
1929c2daa00SOllivier Robert pp->leap = LEAP_NOWARNING;
193c0b746e5SOllivier Robert if (!refclock_process(pp)) {
194c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADTIME);
195c0b746e5SOllivier Robert return;
196c0b746e5SOllivier Robert }
197c0b746e5SOllivier Robert if (pp->coderecv == pp->codeproc) {
198c0b746e5SOllivier Robert refclock_report(peer, CEVNT_TIMEOUT);
199c0b746e5SOllivier Robert return;
200c0b746e5SOllivier Robert }
201c0b746e5SOllivier Robert pp->lastref = pp->lastrec;
202c0b746e5SOllivier Robert record_clock_stats(&peer->srcadr, pp->a_lastcode);
203c0b746e5SOllivier Robert refclock_receive(peer);
204c0b746e5SOllivier Robert }
205c0b746e5SOllivier Robert
206c0b746e5SOllivier Robert #else
2079c2daa00SOllivier Robert int refclock_tpro_bs;
2089c2daa00SOllivier Robert #endif /* REFCLOCK */
209c0b746e5SOllivier Robert