Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_arbiter.c
blob0f246bbb81cd955cf0479646fdc6004a1bca3388
1 /* $NetBSD: refclock_arbiter.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
3 /*
4 * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
5 * Controlled Clock
6 */
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
12 #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
14 #include "ntpd.h"
15 #include "ntp_io.h"
16 #include "ntp_refclock.h"
17 #include "ntp_stdlib.h"
19 #include <stdio.h>
20 #include <ctype.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
41 * on-time = <cr>
42 * i = synchronization flag (' ' = locked, '?' = unlocked)
43 * yy = year of century
44 * ddd = day of year
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
105 struct arbunit {
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 *));
122 * Transfer vector
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
138 static int
139 arb_start(
140 int unit,
141 struct peer *peer
144 register struct arbunit *up;
145 struct refclockproc *pp;
146 int fd;
147 char device[20];
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)))
154 return (0);
157 * Allocate and initialize unit structure
159 if (!(up = (struct arbunit *)emalloc(sizeof(struct arbunit)))) {
160 (void) close(fd);
161 return (0);
163 memset((char *)up, 0, sizeof(struct arbunit));
164 pp = peer->procptr;
165 pp->io.clock_recv = arb_receive;
166 pp->io.srcclock = (caddr_t)peer;
167 pp->io.datalen = 0;
168 pp->io.fd = fd;
169 if (!io_addclock(&pp->io)) {
170 (void) close(fd);
171 free(up);
172 return (0);
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);
183 return (1);
188 * arb_shutdown - shut down the clock
190 static void
191 arb_shutdown(
192 int unit,
193 struct peer *peer
196 register struct arbunit *up;
197 struct refclockproc *pp;
199 pp = peer->procptr;
200 up = (struct arbunit *)pp->unitptr;
201 io_closeclock(&pp->io);
202 free(up);
207 * arb_receive - receive data from the serial interface
209 static void
210 arb_receive(
211 struct recvbuf *rbufp
214 register struct arbunit *up;
215 struct refclockproc *pp;
216 struct peer *peer;
217 l_fp trtmp;
218 int temp;
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;
226 pp = peer->procptr;
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.
244 if (temp == 0)
245 return;
247 pp->lastrec = up->laststamp;
248 up->laststamp = trtmp;
249 if (temp < 3)
250 return;
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);
266 return;
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);
272 else
273 write(pp->io.fd, "B5", 2);
274 return;
276 } else if (!strncmp(tbuf, "LA", 2)) {
277 strcpy(up->latlon, tbuf + 2);
278 write(pp->io.fd, "LO", 2);
279 return;
281 } else if (!strncmp(tbuf, "LO", 2)) {
282 strcat(up->latlon, " ");
283 strcat(up->latlon, tbuf + 2);
284 write(pp->io.fd, "LH", 2);
285 return;
287 } else if (!strncmp(tbuf, "LH", 2)) {
288 strcat(up->latlon, " ");
289 strcat(up->latlon, tbuf + 2);
290 write(pp->io.fd, "DB", 2);
291 return;
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);
297 #ifdef DEBUG
298 if (debug)
299 printf("arbiter: %s\n", up->latlon);
300 #endif
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.
314 up->tcswitch++;
315 if (up->tcswitch <= 1 || temp < LENARB)
316 return;
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);
325 syncchar = ' ';
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);
331 return;
335 * We decode the clock dispersion from the time quality
336 * character.
338 switch (up->qualchar) {
340 case '0': /* locked, max accuracy */
341 pp->disp = 1e-7;
342 pp->lastref = pp->lastrec;
343 break;
345 case '4': /* unlock accuracy < 1 us */
346 pp->disp = 1e-6;
347 break;
349 case '5': /* unlock accuracy < 10 us */
350 pp->disp = 1e-5;
351 break;
353 case '6': /* unlock accuracy < 100 us */
354 pp->disp = 1e-4;
355 break;
357 case '7': /* unlock accuracy < 1 ms */
358 pp->disp = .001;
359 break;
361 case '8': /* unlock accuracy < 10 ms */
362 pp->disp = .01;
363 break;
365 case '9': /* unlock accuracy < 100 ms */
366 pp->disp = .1;
367 break;
369 case 'A': /* unlock accuracy < 1 s */
370 pp->disp = 1;
371 break;
373 case 'B': /* unlock accuracy < 10 s */
374 pp->disp = 10;
375 break;
377 case 'F': /* clock failure */
378 pp->disp = MAXDISPERSE;
379 refclock_report(peer, CEVNT_FAULT);
380 write(pp->io.fd, "B0", 2);
381 return;
383 default:
384 pp->disp = MAXDISPERSE;
385 refclock_report(peer, CEVNT_BADREPLY);
386 write(pp->io.fd, "B0", 2);
387 return;
389 if (syncchar != ' ')
390 pp->leap = LEAP_NOTINSYNC;
391 else
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
412 static void
413 arb_poll(
414 int unit,
415 struct peer *peer
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.
429 pp = peer->procptr;
430 up = (struct arbunit *)pp->unitptr;
431 pp->polls++;
432 up->tcswitch = 0;
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);
442 return;
444 refclock_receive(peer);
445 record_clock_stats(&peer->srcadr, pp->a_lastcode);
446 #ifdef DEBUG
447 if (debug)
448 printf("arbiter: timecode %d %s\n",
449 pp->lencode, pp->a_lastcode);
450 #endif
453 #else
454 int refclock_arbiter_bs;
455 #endif /* REFCLOCK */