source: trunk/third/xntp/xntpd/refclock_irig.c @ 10832

Revision 10832, 7.0 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10831, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * refclock_irig - clock driver for the IRIG audio decoder
3 */
4#ifdef HAVE_CONFIG_H
5#include <config.h>
6#endif
7
8#if defined(REFCLOCK) && defined(IRIG)
9
10#include <stdio.h>
11#include <ctype.h>
12#include <sys/time.h>
13#include <sys/ioccom.h>
14
15#include "ntpd.h"
16#include "ntp_io.h"
17#include "ntp_refclock.h"
18#include "ntp_unixtime.h"
19#include <sys/bsd_audioirig.h>
20#include "ntp_stdlib.h"
21
22/*
23 * This driver supports the IRIG audio decoder. This clever gadget uses
24 * a modified BSD audio driver for the Sun SPARCstation which provides
25 * a timestamp, raw binary timecode, status byte and decoded ASCII
26 * timecode. The data are represented in the structure in the
27 * sys/bsd_audioirig.h header file:
28 *
29 * struct irig_time {
30 *      struct timeval stamp;   timestamp
31 *      u_char  bits[13];       100 IRIG data bits
32 *      u_char  status;         status byte
33 *      char    time[14];       time string (null terminated)
34 *
35 * where stamp represents a timestamp at the zero crossing of the index
36 * marker at the second's epoch, bits is a 13-octet, zero-padded binary-
37 * coded string representing code elements 1 through 100 in the IRIG-B
38 * code format, and status is a status bute, The decoded timestamp is a
39 * 13-octet, null-terminated ASCII string "ddd hh:mm:ss*", where ddd is
40 * the day of year, hh:mm:ss the time of day and * is a status
41 * indicator, with " " indicating valid time and "?" indicating
42 * something wrong.
43 *
44 * The timestamp is in Unix timeval format, consisting of two 32-bit
45 * words, the first of which is the seconds since 1970 and the second is
46 * the fraction of the second in microseconds. The status byte is zero
47 * if (a) the input signal is within amplitude tolerances, (b) the raw
48 * binary timecode contains only valid code elements, (c) 11 position
49 * identifiers have been found at the expected element positions, (d)
50 * the clock status byte contained in the timecode is valid, and (e) a
51 * time determination has been made since the last read() system call.
52 *
53 * The 100 elements of the IRIG-B timecode are numbered from 0 through
54 * 99. Position identifiers occur at elements 0, 9, 19 and every ten
55 * thereafter to 99. The control function (CF) elements begin at element
56 * 50 (CF 1) and extend to element 78 (CF 27). The straight-binary-
57 * seconds (SBS) field, which encodes the seconds of the UTC day, begins
58 * at element 80 (CF 28) and extends to element 97 (CF 44). The encoding
59 * of elements 50 (CF 1) through 78 (CF 27) is device dependent. This
60 * driver presently does not use the CF elements.
61 *
62 * Where feasible, the interface should be operated with signature
63 * control, so that, if the IRIG signal is lost or malformed, the
64 * interface produces an unmodulated signal, rather than possibly random
65 * digits. The driver will declare "unsynchronized" in this case.
66 *
67 * Spectracom Netclock/2 WWVB Synchronized Clock
68 *
69 * Element      CF      Function
70 * -------------------------------------
71 * 55           6       time sync status
72 * 60-63        10-13   bcd year units
73 * 65-68        15-18   bcd year tens
74 *
75 */
76
77/*
78 * IRIG interface definitions
79 */
80#define DEVICE          "/dev/irig%d" /* device name and unit */
81#define PRECISION       (-13)   /* precision assumed (100 us) */
82#define REFID           "IRIG"  /* reference ID */
83#define DESCRIPTION     "IRIG Audio Decoder" /* WRU */
84
85#define NSAMPLES        3       /* stages of median filter */
86#define IRIG_FORMAT     1       /* IRIG timestamp format */
87
88/*
89 * Imported from ntp_timer module
90 */
91extern u_long current_time;     /* current time (s) */
92
93/*
94 * Imported from ntpd module
95 */
96extern int debug;               /* global debug flag */
97
98/*
99 * Function prototypes
100 */
101static  int     irig_start      P((int, struct peer *));
102static  void    irig_shutdown   P((int, struct peer *));
103static  void    irig_poll       P((int, struct peer *));
104
105/*
106 * Transfer vector
107 */
108struct  refclock refclock_irig = {
109        irig_start,             /* start up driver */
110        irig_shutdown,          /* shut down driver */
111        irig_poll,              /* transmit poll message */
112        noentry,                /* not used (old irig_control) */
113        noentry,                /* initialize driver (not used) */
114        noentry,                /* not used (old irig_buginfo) */
115        NOFLAGS                 /* not used */
116};
117
118
119/*
120 * irig_start - open the device and initialize data for processing
121 */
122static int
123irig_start(unit, peer)
124        int unit;
125        struct peer *peer;
126{
127        register struct refclockproc *pp;
128        char device[20];
129        int fd;
130        int format = IRIG_FORMAT;
131
132        /*
133         * Open audio device and set format
134         */
135        (void)sprintf(device, DEVICE, unit);
136        fd = open(device, O_RDONLY | O_NDELAY, 0777);
137        if (fd == -1) {
138                msyslog(LOG_ERR, "irig_start: open of %s: %m", device);
139                return (0);
140        }
141        if (ioctl(fd, AUDIO_IRIG_OPEN, 0) < 0) {
142                msyslog(LOG_ERR, "irig_start: AUDIO_IRIG_OPEN %m");
143                close(fd);
144                return (0);
145        }
146        if (ioctl(fd, AUDIO_IRIG_SETFORMAT, (char *)&format) < 0) {
147                msyslog(LOG_ERR, "irig_start: AUDIO_IRIG_SETFORMAT %m",
148                    DEVICE);
149                close(fd);
150                return (0);
151        }
152        pp = peer->procptr;
153        pp->io.clock_recv = noentry;
154        pp->io.srcclock = (caddr_t)peer;
155        pp->io.datalen = 0;
156        pp->io.fd = fd;
157
158        /*
159         * Initialize miscellaneous variables
160         */
161        peer->precision = PRECISION;
162        pp->clockdesc = DESCRIPTION;
163        memcpy((char *)&pp->refid, REFID, 4);
164        return (1);
165}
166
167
168/*
169 * irig_shutdown - shut down the clock
170 */
171static void
172irig_shutdown(unit, peer)
173        int unit;
174        struct peer *peer;
175{
176        struct refclockproc *pp;
177
178        pp = peer->procptr;
179        io_closeclock(&pp->io);
180}
181
182
183/*
184 * irig_poll - called by the transmit procedure
185 */
186static void
187irig_poll(unit, peer)
188        int unit;
189        struct peer *peer;
190{
191
192        struct refclockproc *pp;
193        struct irig_time buf;
194        char *cp, *dp;
195        u_char *dpt;
196        int i;
197
198        pp = peer->procptr;
199        if (read(pp->io.fd, (char *) &buf, sizeof(buf)) != sizeof(buf)) {
200                refclock_report(peer, CEVNT_FAULT);
201                return;
202        }
203        pp->polls++;
204
205#ifdef DEBUG
206        if (debug) {
207                dpt = (u_char *)&buf;
208                printf("irig: ");
209                for (i = 0; i < sizeof(buf); i++)
210                        printf("%02x", *dpt++);
211                printf("\n");
212        }
213#endif
214
215        buf.stamp.tv_sec += JAN_1970;
216        TVTOTS(&buf.stamp, &pp->lastrec);
217        cp = buf.time;
218        dp = pp->a_lastcode;
219        for (i = 0; i < sizeof(buf.time); i++)
220                *dp++ = *cp++;
221        *--dp = '\0';
222        pp->lencode = dp - pp->a_lastcode;
223
224#ifdef DEBUG
225        if (debug)
226                printf("irig: time %s timecode %d %s\n",
227                    ulfptoa(&pp->lastrec, 6), pp->lencode,
228                    pp->a_lastcode);
229#endif
230        record_clock_stats(&peer->srcadr, pp->a_lastcode);
231
232        /*
233         * Get IRIG time and convert to timestamp format
234         */
235        if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d",
236            &pp->day, &pp->hour, &pp->minute, &pp->second) != 4) {
237                refclock_report(peer, CEVNT_BADREPLY);
238                return;
239        }
240        if (pp->a_lastcode[12] != ' ') {
241                pp->leap = LEAP_NOTINSYNC;
242        } else {
243                pp->leap = 0;
244                pp->lasttime = current_time;
245        }
246
247        /*
248         * Process the new sample in the median filter and determine the
249         * reference clock offset and dispersion. We use lastrec as both
250         * the reference time and receive time in order to avoid being
251         * cute, like setting the reference time later than the receive
252         * time, which may cause a paranoid protocol module to chuck out
253         * the data.
254         */
255        if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
256                refclock_report(peer, CEVNT_BADTIME);
257                return;
258        }
259        refclock_receive(peer, &pp->offset, 0, pp->dispersion,
260            &pp->lastrec, &pp->lastrec, pp->leap);
261}
262
263#else /* not (REFCLOCK && IRIG) */
264int refclock_irig_bs;
265#endif /* not (REFCLOCK && IRIG) */
Note: See TracBrowser for help on using the repository browser.