1 /* $NetBSD: refclock_arbiter.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
4 * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
12 #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
16 #include "ntp_refclock.h"
17 #include "ntp_stdlib.h"
23 * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
24 * The claimed accuracy of this clock is 100 ns relative to the PPS
25 * output when receiving four or more satellites.
27 * The receiver should be configured before starting the NTP daemon, in
28 * order to establish reliable position and operating conditions. It
29 * does not initiate surveying or hold mode. For use with NTP, the
30 * daylight savings time feature should be disables (D0 command) and the
31 * broadcast mode set to operate in UTC (BU command).
33 * The timecode format supported by this driver is selected by the poll
34 * sequence "B5", which initiates a line in the following format to be
35 * repeated once per second until turned off by the "B0" poll sequence.
37 * Format B5 (24 ASCII printing characters):
39 * <cr><lf>i yy ddd hh:mm:ss.000bbb
42 * i = synchronization flag (' ' = locked, '?' = unlocked)
43 * yy = year of century
45 * hh:mm:ss = hours, minutes, seconds
46 * .000 = fraction of second (not used)
47 * bbb = tailing spaces for fill
49 * The alarm condition is indicated by a '?' at i, which indicates the
50 * receiver is not synchronized. In normal operation, a line consisting
51 * of the timecode followed by the time quality character (TQ) followed
52 * by the receiver status string (SR) is written to the clockstats file.
53 * The time quality character is encoded in IEEE P1344 standard:
55 * Format TQ (IEEE P1344 estimated worst-case time quality)
57 * 0 clock locked, maximum accuracy
58 * F clock failure, time not reliable
59 * 4 clock unlocked, accuracy < 1 us
60 * 5 clock unlocked, accuracy < 10 us
61 * 6 clock unlocked, accuracy < 100 us
62 * 7 clock unlocked, accuracy < 1 ms
63 * 8 clock unlocked, accuracy < 10 ms
64 * 9 clock unlocked, accuracy < 100 ms
65 * A clock unlocked, accuracy < 1 s
66 * B clock unlocked, accuracy < 10 s
68 * The status string is encoded as follows:
70 * Format SR (25 ASCII printing characters)
72 * V=vv S=ss T=t P=pdop E=ee
74 * vv = satellites visible
75 * ss = relative signal strength
76 * t = satellites tracked
77 * pdop = position dilution of precision (meters)
78 * ee = hardware errors
80 * If flag4 is set, an additional line consisting of the receiver
81 * latitude (LA), longitude (LO), elevation (LH) (meters), and data
82 * buffer (DB) is written to this file. If channel B is enabled for
83 * deviation mode and connected to a 1-PPS signal, the last two numbers
84 * on the line are the deviation and standard deviation averaged over
85 * the last 15 seconds.
87 * PPS calibration fudge time1 .001240
91 * Interface definitions
93 #define DEVICE "/dev/gps%d" /* device name and unit */
94 #define SPEED232 B9600 /* uart speed (9600 baud) */
95 #define PRECISION (-20) /* precision assumed (about 1 us) */
96 #define REFID "GPS " /* reference ID */
97 #define DESCRIPTION "Arbiter 1088A/B GPS Receiver" /* WRU */
98 #define LENARB 24 /* format B5 timecode length */
99 #define MAXSTA 40 /* max length of status string */
100 #define MAXPOS 80 /* max length of position string */
103 * ARB unit control structure
106 l_fp laststamp
; /* last receive timestamp */
107 int tcswitch
; /* timecode switch/counter */
108 char qualchar
; /* IEEE P1344 quality (TQ command) */
109 char status
[MAXSTA
]; /* receiver status (SR command) */
110 char latlon
[MAXPOS
]; /* receiver position (lat/lon/alt) */
114 * Function prototypes
116 static int arb_start
P((int, struct peer
*));
117 static void arb_shutdown
P((int, struct peer
*));
118 static void arb_receive
P((struct recvbuf
*));
119 static void arb_poll
P((int, struct peer
*));
124 struct refclock refclock_arbiter
= {
125 arb_start
, /* start up driver */
126 arb_shutdown
, /* shut down driver */
127 arb_poll
, /* transmit poll message */
128 noentry
, /* not used (old arb_control) */
129 noentry
, /* initialize driver (not used) */
130 noentry
, /* not used (old arb_buginfo) */
131 NOFLAGS
/* not used */
136 * arb_start - open the devices and initialize data for processing
144 register struct arbunit
*up
;
145 struct refclockproc
*pp
;
150 * Open serial port. Use CLK line discipline, if available.
152 (void)sprintf(device
, DEVICE
, unit
);
153 if (!(fd
= refclock_open(device
, SPEED232
, LDISC_CLK
)))
157 * Allocate and initialize unit structure
159 if (!(up
= (struct arbunit
*)emalloc(sizeof(struct arbunit
)))) {
163 memset((char *)up
, 0, sizeof(struct arbunit
));
165 pp
->io
.clock_recv
= arb_receive
;
166 pp
->io
.srcclock
= (caddr_t
)peer
;
169 if (!io_addclock(&pp
->io
)) {
174 pp
->unitptr
= (caddr_t
)up
;
177 * Initialize miscellaneous variables
179 peer
->precision
= PRECISION
;
180 pp
->clockdesc
= DESCRIPTION
;
181 memcpy((char *)&pp
->refid
, REFID
, 4);
182 write(pp
->io
.fd
, "B0", 2);
188 * arb_shutdown - shut down the clock
196 register struct arbunit
*up
;
197 struct refclockproc
*pp
;
200 up
= (struct arbunit
*)pp
->unitptr
;
201 io_closeclock(&pp
->io
);
207 * arb_receive - receive data from the serial interface
211 struct recvbuf
*rbufp
214 register struct arbunit
*up
;
215 struct refclockproc
*pp
;
219 u_char syncchar
; /* synch indicator */
220 char tbuf
[BMAX
]; /* temp buffer */
223 * Initialize pointers and read the timecode and timestamp
225 peer
= (struct peer
*)rbufp
->recv_srcclock
;
227 up
= (struct arbunit
*)pp
->unitptr
;
228 temp
= refclock_gtlin(rbufp
, tbuf
, BMAX
, &trtmp
);
231 * Note we get a buffer and timestamp for both a <cr> and <lf>,
232 * but only the <cr> timestamp is retained. The program first
233 * sends a TQ and expects the echo followed by the time quality
234 * character. It then sends a B5 starting the timecode broadcast
235 * and expects the echo followed some time later by the on-time
236 * character <cr> and then the <lf> beginning the timecode
237 * itself. Finally, at the <cr> beginning the next timecode at
238 * the next second, the program sends a B0 shutting down the
239 * timecode broadcast.
241 * If flag4 is set, the program snatches the latitude, longitude
242 * and elevation and writes it to the clockstats file.
247 pp
->lastrec
= up
->laststamp
;
248 up
->laststamp
= trtmp
;
252 if (up
->tcswitch
== 0) {
255 * Collect statistics. If nothing is recogized, just
256 * ignore; sometimes the clock doesn't stop spewing
257 * timecodes for awhile after the B0 command.
259 * If flag4 is not set, send TQ, SR, B5. If flag4 is
260 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
261 * median filter is full, send B0.
263 if (!strncmp(tbuf
, "TQ", 2)) {
264 up
->qualchar
= tbuf
[2];
265 write(pp
->io
.fd
, "SR", 2);
268 } else if (!strncmp(tbuf
, "SR", 2)) {
269 strcpy(up
->status
, tbuf
+ 2);
270 if (pp
->sloppyclockflag
& CLK_FLAG4
)
271 write(pp
->io
.fd
, "LA", 2);
273 write(pp
->io
.fd
, "B5", 2);
276 } else if (!strncmp(tbuf
, "LA", 2)) {
277 strcpy(up
->latlon
, tbuf
+ 2);
278 write(pp
->io
.fd
, "LO", 2);
281 } else if (!strncmp(tbuf
, "LO", 2)) {
282 strcat(up
->latlon
, " ");
283 strcat(up
->latlon
, tbuf
+ 2);
284 write(pp
->io
.fd
, "LH", 2);
287 } else if (!strncmp(tbuf
, "LH", 2)) {
288 strcat(up
->latlon
, " ");
289 strcat(up
->latlon
, tbuf
+ 2);
290 write(pp
->io
.fd
, "DB", 2);
293 } else if (!strncmp(tbuf
, "DB", 2)) {
294 strcat(up
->latlon
, " ");
295 strcat(up
->latlon
, tbuf
+ 2);
296 record_clock_stats(&peer
->srcadr
, up
->latlon
);
299 printf("arbiter: %s\n", up
->latlon
);
301 write(pp
->io
.fd
, "B5", 2);
306 * We get down to business, check the timecode format and decode
307 * its contents. If the timecode has valid length, but not in
308 * proper format, we declare bad format and exit. If the
309 * timecode has invalid length, which sometimes occurs when the
310 * B0 amputates the broadcast, we just quietly steal away. Note
311 * that the time quality character and receiver status string is
312 * tacked on the end for clockstats display.
315 if (up
->tcswitch
<= 1 || temp
< LENARB
)
319 * Timecode format B5: "i yy ddd hh:mm:ss.000 "
321 strncpy(pp
->a_lastcode
, tbuf
, BMAX
);
322 pp
->a_lastcode
[LENARB
- 2] = up
->qualchar
;
323 strcat(pp
->a_lastcode
, up
->status
);
324 pp
->lencode
= strlen(pp
->a_lastcode
);
326 if (sscanf(pp
->a_lastcode
, "%c%2d %3d %2d:%2d:%2d",
327 &syncchar
, &pp
->year
, &pp
->day
, &pp
->hour
,
328 &pp
->minute
, &pp
->second
) != 6) {
329 refclock_report(peer
, CEVNT_BADREPLY
);
330 write(pp
->io
.fd
, "B0", 2);
335 * We decode the clock dispersion from the time quality
338 switch (up
->qualchar
) {
340 case '0': /* locked, max accuracy */
342 pp
->lastref
= pp
->lastrec
;
345 case '4': /* unlock accuracy < 1 us */
349 case '5': /* unlock accuracy < 10 us */
353 case '6': /* unlock accuracy < 100 us */
357 case '7': /* unlock accuracy < 1 ms */
361 case '8': /* unlock accuracy < 10 ms */
365 case '9': /* unlock accuracy < 100 ms */
369 case 'A': /* unlock accuracy < 1 s */
373 case 'B': /* unlock accuracy < 10 s */
377 case 'F': /* clock failure */
378 pp
->disp
= MAXDISPERSE
;
379 refclock_report(peer
, CEVNT_FAULT
);
380 write(pp
->io
.fd
, "B0", 2);
384 pp
->disp
= MAXDISPERSE
;
385 refclock_report(peer
, CEVNT_BADREPLY
);
386 write(pp
->io
.fd
, "B0", 2);
390 pp
->leap
= LEAP_NOTINSYNC
;
392 pp
->leap
= LEAP_NOWARNING
;
395 * Process the new sample in the median filter and determine the
396 * timecode timestamp.
398 if (!refclock_process(pp
))
399 refclock_report(peer
, CEVNT_BADTIME
);
400 else if (peer
->disp
> MAXDISTANCE
)
401 refclock_receive(peer
);
403 if (up
->tcswitch
>= MAXSTAGE
) {
404 write(pp
->io
.fd
, "B0", 2);
410 * arb_poll - called by the transmit procedure
418 register struct arbunit
*up
;
419 struct refclockproc
*pp
;
422 * Time to poll the clock. The Arbiter clock responds to a "B5"
423 * by returning a timecode in the format specified above.
424 * Transmission occurs once per second, unless turned off by a
425 * "B0". Note there is no checking on state, since this may not
426 * be the only customer reading the clock. Only one customer
427 * need poll the clock; all others just listen in.
430 up
= (struct arbunit
*)pp
->unitptr
;
433 if (write(pp
->io
.fd
, "TQ", 2) != 2)
434 refclock_report(peer
, CEVNT_FAULT
);
437 * Process median filter samples. If none received, declare a
438 * timeout and keep going.
440 if (pp
->coderecv
== pp
->codeproc
) {
441 refclock_report(peer
, CEVNT_TIMEOUT
);
444 refclock_receive(peer
);
445 record_clock_stats(&peer
->srcadr
, pp
->a_lastcode
);
448 printf("arbiter: timecode %d %s\n",
449 pp
->lencode
, pp
->a_lastcode
);
454 int refclock_arbiter_bs
;
455 #endif /* REFCLOCK */