]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpd/refclock_arbiter.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / ntpd / refclock_arbiter.c
1 /*
2  * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
3  *      Controlled Clock
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
11
12 #include "ntpd.h"
13 #include "ntp_io.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
16
17 #include <stdio.h>
18 #include <ctype.h>
19
20 /*
21  * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
22  * The claimed accuracy of this clock is 100 ns relative to the PPS
23  * output when receiving four or more satellites.
24  *
25  * The receiver should be configured before starting the NTP daemon, in
26  * order to establish reliable position and operating conditions. It
27  * does not initiate surveying or hold mode. For use with NTP, the
28  * daylight savings time feature should be disables (D0 command) and the
29  * broadcast mode set to operate in UTC (BU command).
30  *
31  * The timecode format supported by this driver is selected by the poll
32  * sequence "B5", which initiates a line in the following format to be
33  * repeated once per second until turned off by the "B0" poll sequence.
34  *
35  * Format B5 (24 ASCII printing characters):
36  *
37  * <cr><lf>i yy ddd hh:mm:ss.000bbb  
38  *
39  *      on-time = <cr>
40  *      i = synchronization flag (' ' = locked, '?' = unlocked)
41  *      yy = year of century
42  *      ddd = day of year
43  *      hh:mm:ss = hours, minutes, seconds
44  *      .000 = fraction of second (not used)
45  *      bbb = tailing spaces for fill
46  *
47  * The alarm condition is indicated by a '?' at i, which indicates the
48  * receiver is not synchronized. In normal operation, a line consisting
49  * of the timecode followed by the time quality character (TQ) followed
50  * by the receiver status string (SR) is written to the clockstats file.
51  * The time quality character is encoded in IEEE P1344 standard:
52  *
53  * Format TQ (IEEE P1344 estimated worst-case time quality)
54  *
55  *      0       clock locked, maximum accuracy
56  *      F       clock failure, time not reliable
57  *      4       clock unlocked, accuracy < 1 us
58  *      5       clock unlocked, accuracy < 10 us
59  *      6       clock unlocked, accuracy < 100 us
60  *      7       clock unlocked, accuracy < 1 ms
61  *      8       clock unlocked, accuracy < 10 ms
62  *      9       clock unlocked, accuracy < 100 ms
63  *      A       clock unlocked, accuracy < 1 s
64  *      B       clock unlocked, accuracy < 10 s
65  *
66  * The status string is encoded as follows:
67  *
68  * Format SR (25 ASCII printing characters)
69  *
70  *      V=vv S=ss T=t P=pdop E=ee
71  *
72  *      vv = satellites visible
73  *      ss = relative signal strength
74  *      t = satellites tracked
75  *      pdop = position dilution of precision (meters)
76  *      ee = hardware errors
77  *
78  * If flag4 is set, an additional line consisting of the receiver
79  * latitude (LA), longitude (LO), elevation (LH) (meters), and data
80  * buffer (DB) is written to this file. If channel B is enabled for
81  * deviation mode and connected to a 1-PPS signal, the last two numbers
82  * on the line are the deviation and standard deviation averaged over
83  * the last 15 seconds.
84  *
85  * PPS calibration fudge time1 .001240
86  */
87
88 /*
89  * Interface definitions
90  */
91 #define DEVICE          "/dev/gps%d" /* device name and unit */
92 #define SPEED232        B9600   /* uart speed (9600 baud) */
93 #define PRECISION       (-20)   /* precision assumed (about 1 us) */
94 #define REFID           "GPS "  /* reference ID */
95 #define DESCRIPTION     "Arbiter 1088A/B GPS Receiver" /* WRU */
96 #define LENARB          24      /* format B5 timecode length */
97 #define MAXSTA          40      /* max length of status string */
98 #define MAXPOS          80      /* max length of position string */
99
100 /*
101  * ARB unit control structure
102  */
103 struct arbunit {
104         l_fp    laststamp;      /* last receive timestamp */
105         int     tcswitch;       /* timecode switch/counter */
106         char    qualchar;       /* IEEE P1344 quality (TQ command) */
107         char    status[MAXSTA]; /* receiver status (SR command) */
108         char    latlon[MAXPOS]; /* receiver position (lat/lon/alt) */
109 };
110
111 /*
112  * Function prototypes
113  */
114 static  int     arb_start       P((int, struct peer *));
115 static  void    arb_shutdown    P((int, struct peer *));
116 static  void    arb_receive     P((struct recvbuf *));
117 static  void    arb_poll        P((int, struct peer *));
118
119 /*
120  * Transfer vector
121  */
122 struct  refclock refclock_arbiter = {
123         arb_start,              /* start up driver */
124         arb_shutdown,           /* shut down driver */
125         arb_poll,               /* transmit poll message */
126         noentry,                /* not used (old arb_control) */
127         noentry,                /* initialize driver (not used) */
128         noentry,                /* not used (old arb_buginfo) */
129         NOFLAGS                 /* not used */
130 };
131
132
133 /*
134  * arb_start - open the devices and initialize data for processing
135  */
136 static int
137 arb_start(
138         int unit,
139         struct peer *peer
140         )
141 {
142         register struct arbunit *up;
143         struct refclockproc *pp;
144         int fd;
145         char device[20];
146
147         /*
148          * Open serial port. Use CLK line discipline, if available.
149          */
150         (void)sprintf(device, DEVICE, unit);
151         if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
152                 return (0);
153
154         /*
155          * Allocate and initialize unit structure
156          */
157         if (!(up = (struct arbunit *)emalloc(sizeof(struct arbunit)))) {
158                 (void) close(fd);
159                 return (0);
160         }
161         memset((char *)up, 0, sizeof(struct arbunit));
162         pp = peer->procptr;
163         pp->io.clock_recv = arb_receive;
164         pp->io.srcclock = (caddr_t)peer;
165         pp->io.datalen = 0;
166         pp->io.fd = fd;
167         if (!io_addclock(&pp->io)) {
168                 (void) close(fd);
169                 free(up);
170                 return (0);
171         }
172         pp->unitptr = (caddr_t)up;
173
174         /*
175          * Initialize miscellaneous variables
176          */
177         peer->precision = PRECISION;
178         pp->clockdesc = DESCRIPTION;
179         memcpy((char *)&pp->refid, REFID, 4);
180         write(pp->io.fd, "B0", 2);
181         return (1);
182 }
183
184
185 /*
186  * arb_shutdown - shut down the clock
187  */
188 static void
189 arb_shutdown(
190         int unit,
191         struct peer *peer
192         )
193 {
194         register struct arbunit *up;
195         struct refclockproc *pp;
196
197         pp = peer->procptr;
198         up = (struct arbunit *)pp->unitptr;
199         io_closeclock(&pp->io);
200         free(up);
201 }
202
203
204 /*
205  * arb_receive - receive data from the serial interface
206  */
207 static void
208 arb_receive(
209         struct recvbuf *rbufp
210         )
211 {
212         register struct arbunit *up;
213         struct refclockproc *pp;
214         struct peer *peer;
215         l_fp trtmp;
216         int temp;
217         u_char  syncchar;               /* synch indicator */
218         char    tbuf[BMAX];             /* temp buffer */
219
220         /*
221          * Initialize pointers and read the timecode and timestamp
222          */
223         peer = (struct peer *)rbufp->recv_srcclock;
224         pp = peer->procptr;
225         up = (struct arbunit *)pp->unitptr;
226         temp = refclock_gtlin(rbufp, tbuf, BMAX, &trtmp);
227
228         /*
229          * Note we get a buffer and timestamp for both a <cr> and <lf>,
230          * but only the <cr> timestamp is retained. The program first
231          * sends a TQ and expects the echo followed by the time quality
232          * character. It then sends a B5 starting the timecode broadcast
233          * and expects the echo followed some time later by the on-time
234          * character <cr> and then the <lf> beginning the timecode
235          * itself. Finally, at the <cr> beginning the next timecode at
236          * the next second, the program sends a B0 shutting down the
237          * timecode broadcast.
238          *
239          * If flag4 is set, the program snatches the latitude, longitude
240          * and elevation and writes it to the clockstats file.
241          */
242         if (temp == 0)
243                 return;
244
245         pp->lastrec = up->laststamp;
246         up->laststamp = trtmp;
247         if (temp < 3)
248                 return;
249
250         if (up->tcswitch == 0) {
251
252                 /*
253                  * Collect statistics. If nothing is recogized, just
254                  * ignore; sometimes the clock doesn't stop spewing
255                  * timecodes for awhile after the B0 command.
256                  *
257                  * If flag4 is not set, send TQ, SR, B5. If flag4 is
258                  * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
259                  * median filter is full, send B0.
260                  */
261                 if (!strncmp(tbuf, "TQ", 2)) {
262                         up->qualchar = tbuf[2];
263                         write(pp->io.fd, "SR", 2);
264                         return;
265
266                 } else if (!strncmp(tbuf, "SR", 2)) {
267                         strcpy(up->status, tbuf + 2);
268                         if (pp->sloppyclockflag & CLK_FLAG4)
269                                 write(pp->io.fd, "LA", 2);
270                         else
271                                 write(pp->io.fd, "B5", 2);
272                         return;
273
274                 } else if (!strncmp(tbuf, "LA", 2)) {
275                         strcpy(up->latlon, tbuf + 2);
276                         write(pp->io.fd, "LO", 2);
277                         return;
278
279                 } else if (!strncmp(tbuf, "LO", 2)) {
280                         strcat(up->latlon, " ");
281                         strcat(up->latlon, tbuf + 2);
282                         write(pp->io.fd, "LH", 2);
283                         return;
284
285                 } else if (!strncmp(tbuf, "LH", 2)) {
286                         strcat(up->latlon, " ");
287                         strcat(up->latlon, tbuf + 2);
288                         write(pp->io.fd, "DB", 2);
289                         return;
290
291                 } else if (!strncmp(tbuf, "DB", 2)) {
292                         strcat(up->latlon, " ");
293                         strcat(up->latlon, tbuf + 2);
294                         record_clock_stats(&peer->srcadr, up->latlon);
295 #ifdef DEBUG
296                         if (debug)
297                                 printf("arbiter: %s\n", up->latlon);
298 #endif
299                         write(pp->io.fd, "B5", 2);
300                 }
301         }
302
303         /*
304          * We get down to business, check the timecode format and decode
305          * its contents. If the timecode has valid length, but not in
306          * proper format, we declare bad format and exit. If the
307          * timecode has invalid length, which sometimes occurs when the
308          * B0 amputates the broadcast, we just quietly steal away. Note
309          * that the time quality character and receiver status string is
310          * tacked on the end for clockstats display. 
311          */
312         up->tcswitch++;
313         if (up->tcswitch <= 1 || temp < LENARB)
314                 return;
315
316         /*
317          * Timecode format B5: "i yy ddd hh:mm:ss.000   "
318          */
319         strncpy(pp->a_lastcode, tbuf, BMAX);
320         pp->a_lastcode[LENARB - 2] = up->qualchar;
321         strcat(pp->a_lastcode, up->status);
322         pp->lencode = strlen(pp->a_lastcode);
323         syncchar = ' ';
324         if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
325             &syncchar, &pp->year, &pp->day, &pp->hour,
326             &pp->minute, &pp->second) != 6) {
327                 refclock_report(peer, CEVNT_BADREPLY);
328                 write(pp->io.fd, "B0", 2);
329                 return;
330         }
331
332         /*
333          * We decode the clock dispersion from the time quality
334          * character.
335          */
336         switch (up->qualchar) {
337
338             case '0':           /* locked, max accuracy */
339                 pp->disp = 1e-7;
340                 pp->lastref = pp->lastrec;
341                 break;
342
343             case '4':           /* unlock accuracy < 1 us */
344                 pp->disp = 1e-6;
345                 break;
346
347             case '5':           /* unlock accuracy < 10 us */
348                 pp->disp = 1e-5;
349                 break;
350
351             case '6':           /* unlock accuracy < 100 us */
352                 pp->disp = 1e-4;
353                 break;
354
355             case '7':           /* unlock accuracy < 1 ms */
356                 pp->disp = .001;
357                 break;
358
359             case '8':           /* unlock accuracy < 10 ms */
360                 pp->disp = .01;
361                 break;
362
363             case '9':           /* unlock accuracy < 100 ms */
364                 pp->disp = .1;
365                 break;
366
367             case 'A':           /* unlock accuracy < 1 s */
368                 pp->disp = 1;
369                 break;
370
371             case 'B':           /* unlock accuracy < 10 s */
372                 pp->disp = 10;
373                 break;
374
375             case 'F':           /* clock failure */
376                 pp->disp = MAXDISPERSE;
377                 refclock_report(peer, CEVNT_FAULT);
378                 write(pp->io.fd, "B0", 2);
379                 return;
380
381             default:
382                 pp->disp = MAXDISPERSE;
383                 refclock_report(peer, CEVNT_BADREPLY);
384                 write(pp->io.fd, "B0", 2);
385                 return;
386         }
387         if (syncchar != ' ')
388                 pp->leap = LEAP_NOTINSYNC;
389         else
390                 pp->leap = LEAP_NOWARNING;
391
392         /*
393          * Process the new sample in the median filter and determine the
394          * timecode timestamp.
395          */
396         if (!refclock_process(pp))
397                 refclock_report(peer, CEVNT_BADTIME);
398         else if (peer->disp > MAXDISTANCE)
399                 refclock_receive(peer);
400
401         if (up->tcswitch >= MAXSTAGE) {
402                 write(pp->io.fd, "B0", 2);
403         }
404 }
405
406
407 /*
408  * arb_poll - called by the transmit procedure
409  */
410 static void
411 arb_poll(
412         int unit,
413         struct peer *peer
414         )
415 {
416         register struct arbunit *up;
417         struct refclockproc *pp;
418
419         /*
420          * Time to poll the clock. The Arbiter clock responds to a "B5"
421          * by returning a timecode in the format specified above.
422          * Transmission occurs once per second, unless turned off by a
423          * "B0". Note there is no checking on state, since this may not
424          * be the only customer reading the clock. Only one customer
425          * need poll the clock; all others just listen in.
426          */
427         pp = peer->procptr;
428         up = (struct arbunit *)pp->unitptr;
429         pp->polls++;
430         up->tcswitch = 0;
431         if (write(pp->io.fd, "TQ", 2) != 2)
432                 refclock_report(peer, CEVNT_FAULT);
433
434         /*
435          * Process median filter samples. If none received, declare a
436          * timeout and keep going.
437          */
438         if (pp->coderecv == pp->codeproc) {
439                 refclock_report(peer, CEVNT_TIMEOUT);
440                 return;
441         }
442         refclock_receive(peer);
443         record_clock_stats(&peer->srcadr, pp->a_lastcode);
444 #ifdef DEBUG
445         if (debug)
446                 printf("arbiter: timecode %d %s\n",
447                    pp->lencode, pp->a_lastcode);
448 #endif
449 }
450
451 #else
452 int refclock_arbiter_bs;
453 #endif /* REFCLOCK */