1 /*        $NetBSD: refclock_arbiter.c,v 1.6 2024/08/18 20:47:18 christos Exp $  */
2 
3 /*
4  * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
5  *        Controlled Clock
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
13 
14 #include "ntpd.h"
15 #include "ntp_io.h"
16 #include "ntp_refclock.h"
17 #include "ntp_stdlib.h"
18 
19 #include <stdio.h>
20 #include <ctype.h>
21 
22 /*
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.
26  *
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).
32  *
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.
36  *
37  * Format B5 (24 ASCII printing characters):
38  *
39  * <cr><lf>i yy ddd hh:mm:ss.000bbb
40  *
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
48  *
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:
54  *
55  * Format TQ (IEEE P1344 estimated worst-case time quality)
56  *
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
67  *
68  * The status string is encoded as follows:
69  *
70  * Format SR (25 ASCII printing characters)
71  *
72  *        V=vv S=ss T=t P=pdop E=ee
73  *
74  *        vv = satellites visible
75  *        ss = relative signal strength
76  *        t = satellites tracked
77  *        pdop = position dilution of precision (meters)
78  *        ee = hardware errors
79  *
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.
86  *
87  * PPS calibration fudge time1 .001240
88  */
89 
90 /*
91  * Interface definitions
92  */
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 */
101 
102 #ifdef PRE_NTP420
103 #define MODE ttlmax
104 #else
105 #define MODE ttl
106 #endif
107 
108 #define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
109 #define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
110 
111 /*
112  * ARB unit control structure
113  */
114 struct arbunit {
115           l_fp      laststamp;          /* last receive timestamp */
116           int       tcswitch; /* timecode switch/counter */
117           char      qualchar; /* IEEE P1344 quality (TQ command) */
118           char      status[MAXSTA];     /* receiver status (SR command) */
119           char      latlon[MAXPOS];     /* receiver position (lat/lon/alt) */
120 };
121 
122 /*
123  * Function prototypes
124  */
125 static    int       arb_start (int, struct peer *);
126 static    void      arb_shutdown        (int, struct peer *);
127 static    void      arb_receive         (struct recvbuf *);
128 static    void      arb_poll  (int, struct peer *);
129 
130 /*
131  * Transfer vector
132  */
133 struct    refclock refclock_arbiter = {
134           arb_start,                    /* start up driver */
135           arb_shutdown,                 /* shut down driver */
136           arb_poll,           /* transmit poll message */
137           noentry,            /* not used (old arb_control) */
138           noentry,            /* initialize driver (not used) */
139           noentry,            /* not used (old arb_buginfo) */
140           NOFLAGS                       /* not used */
141 };
142 
143 
144 /*
145  * arb_start - open the devices and initialize data for processing
146  */
147 static int
arb_start(int unit,struct peer * peer)148 arb_start(
149           int unit,
150           struct peer *peer
151           )
152 {
153           register struct arbunit *up;
154           struct refclockproc *pp;
155           int fd;
156           char device[20];
157 
158           /*
159            * Open serial port. Use CLK line discipline, if available.
160            */
161           snprintf(device, sizeof(device), DEVICE, unit);
162           fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_CLK);
163           if (fd <= 0)
164                     return (0);
165 
166           /*
167            * Allocate and initialize unit structure
168            */
169           up = emalloc_zero(sizeof(*up));
170           pp = peer->procptr;
171           pp->io.clock_recv = arb_receive;
172           pp->io.srcclock = peer;
173           pp->io.datalen = 0;
174           pp->io.fd = fd;
175           if (!io_addclock(&pp->io)) {
176                     close(fd);
177                     pp->io.fd = -1;
178                     free(up);
179                     return (0);
180           }
181           pp->unitptr = up;
182 
183           /*
184            * Initialize miscellaneous variables
185            */
186           peer->precision = PRECISION;
187           pp->clockdesc = DESCRIPTION;
188           memcpy((char *)&pp->refid, REFID, 4);
189           if (peer->MODE > 1) {
190                     msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
191                     close(fd);
192                     pp->io.fd = -1;
193                     free(up);
194                     return (0);
195           }
196 #ifdef DEBUG
197           if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
198 #endif
199           refclock_write(peer, COMMAND_HALT_BCAST, 2, "HALT_BCAST");
200           return (1);
201 }
202 
203 
204 /*
205  * arb_shutdown - shut down the clock
206  */
207 static void
arb_shutdown(int unit,struct peer * peer)208 arb_shutdown(
209           int unit,
210           struct peer *peer
211           )
212 {
213           register struct arbunit *up;
214           struct refclockproc *pp;
215 
216           pp = peer->procptr;
217           up = pp->unitptr;
218           if (-1 != pp->io.fd)
219                     io_closeclock(&pp->io);
220           if (NULL != up)
221                     free(up);
222 }
223 
224 
225 /*
226  * arb_receive - receive data from the serial interface
227  */
228 static void
arb_receive(struct recvbuf * rbufp)229 arb_receive(
230           struct recvbuf *rbufp
231           )
232 {
233           register struct arbunit *up;
234           struct refclockproc *pp;
235           struct peer *peer;
236           l_fp trtmp;
237           int temp;
238           u_char    syncchar;           /* synch indicator */
239           char      tbuf[BMAX];                   /* temp buffer */
240 
241           /*
242            * Initialize pointers and read the timecode and timestamp
243            */
244           peer = rbufp->recv_peer;
245           pp = peer->procptr;
246           up = pp->unitptr;
247           temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp);
248 
249           /*
250            * Note we get a buffer and timestamp for both a <cr> and <lf>,
251            * but only the <cr> timestamp is retained. The program first
252            * sends a TQ and expects the echo followed by the time quality
253            * character. It then sends a B5 starting the timecode broadcast
254            * and expects the echo followed some time later by the on-time
255            * character <cr> and then the <lf> beginning the timecode
256            * itself. Finally, at the <cr> beginning the next timecode at
257            * the next second, the program sends a B0 shutting down the
258            * timecode broadcast.
259            *
260            * If flag4 is set, the program snatches the latitude, longitude
261            * and elevation and writes it to the clockstats file.
262            */
263           if (temp == 0)
264                     return;
265 
266           pp->lastrec = up->laststamp;
267           up->laststamp = trtmp;
268           if (temp < 3)
269                     return;
270 
271           if (up->tcswitch == 0) {
272 
273                     /*
274                      * Collect statistics. If nothing is recogized, just
275                      * ignore; sometimes the clock doesn't stop spewing
276                      * timecodes for awhile after the B0 command.
277                      *
278                      * If flag4 is not set, send TQ, SR, B5. If flag4 is
279                      * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
280                      * median filter is full, send B0.
281                      */
282                     if (!strncmp(tbuf, "TQ", 2)) {
283                               up->qualchar = tbuf[2];
284                               refclock_write(peer, "SR", 2, "SR");
285                               return;
286 
287                     } else if (!strncmp(tbuf, "SR", 2)) {
288                               strlcpy(up->status, tbuf + 2,
289                                         sizeof(up->status));
290                               if (pp->sloppyclockflag & CLK_FLAG4)
291                                   refclock_write(peer, "LA", 2, "LA");
292                               else
293                                   refclock_write(peer, COMMAND_START_BCAST, 2,
294                                         COMMAND_START_BCAST);
295                               return;
296 
297                     } else if (!strncmp(tbuf, "LA", 2)) {
298                               strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon));
299                               refclock_write(peer, "LO", 2, "LO");
300                               return;
301 
302                     } else if (!strncmp(tbuf, "LO", 2)) {
303                               strlcat(up->latlon, " ", sizeof(up->latlon));
304                               strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
305                               refclock_write(peer, "LH", 2, "LH");
306                               return;
307 
308                     } else if (!strncmp(tbuf, "LH", 2)) {
309                               strlcat(up->latlon, " ", sizeof(up->latlon));
310                               strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
311                               refclock_write(peer, "DB", 2, "DB");
312                               return;
313 
314                     } else if (!strncmp(tbuf, "DB", 2)) {
315                               strlcat(up->latlon, " ", sizeof(up->latlon));
316                               strlcat(up->latlon, tbuf + 2, sizeof(up->latlon));
317                               record_clock_stats(&peer->srcadr, up->latlon);
318 #ifdef DEBUG
319                               if (debug)
320                                         printf("arbiter: %s\n", up->latlon);
321 #endif
322                               refclock_write(peer, COMMAND_START_BCAST, 2,
323                                                COMMAND_START_BCAST);
324                     }
325           }
326 
327           /*
328            * We get down to business, check the timecode format and decode
329            * its contents. If the timecode has valid length, but not in
330            * proper format, we declare bad format and exit. If the
331            * timecode has invalid length, which sometimes occurs when the
332            * B0 amputates the broadcast, we just quietly steal away. Note
333            * that the time quality character and receiver status string is
334            * tacked on the end for clockstats display.
335            */
336           up->tcswitch++;
337           if (up->tcswitch <= 1 || temp < LENARB)
338                     return;
339 
340           /*
341            * Timecode format B5: "i yy ddd hh:mm:ss.000   "
342            */
343           strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode));
344           pp->a_lastcode[LENARB - 2] = up->qualchar;
345           strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode));
346           pp->lencode = strlen(pp->a_lastcode);
347           syncchar = ' ';
348           if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
349               &syncchar, &pp->year, &pp->day, &pp->hour,
350               &pp->minute, &pp->second) != 6) {
351                     refclock_report(peer, CEVNT_BADREPLY);
352                     refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST);
353                     return;
354           }
355 
356           /*
357            * We decode the clock dispersion from the time quality
358            * character.
359            */
360           switch (up->qualchar) {
361 
362               case '0':                 /* locked, max accuracy */
363                     pp->disp = 1e-7;
364                     pp->lastref = pp->lastrec;
365                     break;
366 
367               case '4':                 /* unlock accuracy < 1 us */
368                     pp->disp = 1e-6;
369                     break;
370 
371               case '5':                 /* unlock accuracy < 10 us */
372                     pp->disp = 1e-5;
373                     break;
374 
375               case '6':                 /* unlock accuracy < 100 us */
376                     pp->disp = 1e-4;
377                     break;
378 
379               case '7':                 /* unlock accuracy < 1 ms */
380                     pp->disp = .001;
381                     break;
382 
383               case '8':                 /* unlock accuracy < 10 ms */
384                     pp->disp = .01;
385                     break;
386 
387               case '9':                 /* unlock accuracy < 100 ms */
388                     pp->disp = .1;
389                     break;
390 
391               case 'A':                 /* unlock accuracy < 1 s */
392                     pp->disp = 1;
393                     break;
394 
395               case 'B':                 /* unlock accuracy < 10 s */
396                     pp->disp = 10;
397                     break;
398 
399               case 'F':                 /* clock failure */
400                     pp->disp = MAXDISPERSE;
401                     refclock_report(peer, CEVNT_FAULT);
402                     refclock_write(peer, COMMAND_HALT_BCAST, 2,
403                                      COMMAND_HALT_BCAST);
404                     return;
405 
406               default:
407                     pp->disp = MAXDISPERSE;
408                     refclock_report(peer, CEVNT_BADREPLY);
409                     refclock_write(peer, COMMAND_HALT_BCAST, 2,
410                                      COMMAND_HALT_BCAST);
411                     return;
412           }
413           if (syncchar != ' ')
414                     pp->leap = LEAP_NOTINSYNC;
415           else
416                     pp->leap = LEAP_NOWARNING;
417 
418           /*
419            * Process the new sample in the median filter and determine the
420            * timecode timestamp.
421            */
422           if (!refclock_process(pp))
423                     refclock_report(peer, CEVNT_BADTIME);
424           else if (peer->disp > MAXDISTANCE)
425                     refclock_receive(peer);
426 
427           /* if (up->tcswitch >= MAXSTAGE) { */
428           refclock_write(peer, COMMAND_HALT_BCAST, 2, COMMAND_HALT_BCAST);
429           /* } */
430 }
431 
432 
433 /*
434  * arb_poll - called by the transmit procedure
435  */
436 static void
arb_poll(int unit,struct peer * peer)437 arb_poll(
438           int unit,
439           struct peer *peer
440           )
441 {
442           register struct arbunit *up;
443           struct refclockproc *pp;
444 
445           /*
446            * Time to poll the clock. The Arbiter clock responds to a "B5"
447            * by returning a timecode in the format specified above.
448            * Transmission occurs once per second, unless turned off by a
449            * "B0". Note there is no checking on state, since this may not
450            * be the only customer reading the clock. Only one customer
451            * need poll the clock; all others just listen in.
452            */
453           pp = peer->procptr;
454           up = pp->unitptr;
455           pp->polls++;
456           up->tcswitch = 0;
457           if (refclock_write(peer, "TQ", 2, "TQ") != 2)
458                     refclock_report(peer, CEVNT_FAULT);
459 
460           /*
461            * Process median filter samples. If none received, declare a
462            * timeout and keep going.
463            */
464           if (pp->coderecv == pp->codeproc) {
465                     refclock_report(peer, CEVNT_TIMEOUT);
466                     return;
467           }
468           refclock_receive(peer);
469           record_clock_stats(&peer->srcadr, pp->a_lastcode);
470 #ifdef DEBUG
471           if (debug)
472                     printf("arbiter: timecode %d %s\n",
473                        pp->lencode, pp->a_lastcode);
474 #endif
475 }
476 
477 #else
478 NONEMPTY_TRANSLATION_UNIT
479 #endif /* REFCLOCK */
480