Coverage Report

Created: 2023-03-26 07:11

/src/ntp-dev/ntpd/refclock_true.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_true - clock driver for the Kinemetrics/TrueTime receivers
3
 *  Receiver Version 3.0C - tested plain, with CLKLDISC
4
 *  Development work being done:
5
 *      - Support TL-3 WWV TOD receiver
6
 */
7
8
#ifdef HAVE_CONFIG_H
9
#include <config.h>
10
#endif
11
12
#if defined(REFCLOCK) && defined(CLOCK_TRUETIME)
13
14
#include <stdio.h>
15
#include <ctype.h>
16
17
#include "ntpd.h"
18
#include "ntp_io.h"
19
#include "ntp_refclock.h"
20
#include "ntp_unixtime.h"
21
#include "ntp_stdlib.h"
22
23
#ifdef SYS_WINNT
24
extern int async_write(int, const void *, unsigned int);
25
#undef write
26
#define write(fd, data, octets) async_write(fd, data, octets)
27
#endif
28
29
/* This should be an atom clock but those are very hard to build.
30
 *
31
 * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch
32
 * of TTL input and output pins, all brought out to the back panel.  If you
33
 * wire a PPS signal (such as the TTL PPS coming out of a GOES or other
34
 * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the
35
 * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the
36
 * number of uSecs since the last PPS upward swing, mediated by reading OUT0
37
 * to find out if the counter has wrapped around (this happens if more than
38
 * 65535us (65ms) elapses between the PPS event and our being called.)
39
 */
40
#ifdef CLOCK_PPS720
41
# undef min /* XXX */
42
# undef max /* XXX */
43
# include <machine/inline.h>
44
# include <sys/pcl720.h>
45
# include <sys/i8253.h>
46
# define PCL720_IOB 0x2a0 /* XXX */
47
# define PCL720_CTR 0   /* XXX */
48
#endif
49
50
/*
51
 * Support for Kinemetrics Truetime Receivers
52
 *  GOES:           (468-DC, usable with GPS->GOES converting antenna)
53
 *  GPS/TM-TMD: 
54
 *  XL-DC:    (a 151-602-210, reported by the driver as a GPS/TM-TMD)
55
 *  GPS-800 TCU:  (an 805-957 with the RS232 Talker/Listener module)
56
 *      TL-3:           3 channel WWV/H receiver w/ IRIG and RS-232 outputs
57
 *  OM-DC:    getting stale ("OMEGA")
58
 *
59
 * Most of this code is originally from refclock_wwvb.c with thanks.
60
 * It has been so mangled that wwvb is not a recognizable ancestor.
61
 *
62
 * Timcode format: ADDD:HH:MM:SSQCL
63
 *  A - control A   (this is stripped before we see it)
64
 *  Q - Quality indication  (see below)
65
 *  C - Carriage return
66
 *  L - Line feed
67
 *
68
 * Quality codes indicate possible error of
69
 *   468-DC GOES Receiver:
70
 *   GPS-TM/TMD Receiver: (default quality codes for XL-DC)
71
 *       ?     +/- 1  milliseconds  #     +/- 100 microseconds
72
 *       *     +/- 10 microseconds  .     +/- 1   microsecond
73
 *     space   less than 1 microsecond
74
 *   TL-3 Receiver: (default quality codes for TL-3)
75
 *       ?     unknown quality (receiver is unlocked)
76
 *     space   +/- 5 milliseconds
77
 *   OM-DC OMEGA Receiver: (default quality codes for OMEGA)
78
 *   WARNING OMEGA navigation system is no longer existent
79
 *       >     >+- 5 seconds
80
 *       ?     >+/- 500 milliseconds    #     >+/- 50 milliseconds
81
 *       *     >+/- 5 milliseconds      .     >+/- 1 millisecond
82
 *      A-H    less than 1 millisecond.  Character indicates which station
83
 *         is being received as follows:
84
 *         A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
85
 *         E = La Reunion, F = Argentina, G = Australia, H = Japan.
86
 *
87
 * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
88
 *
89
 * Notes on 468-DC and OMEGA receiver:
90
 *
91
 * Send the clock a 'R' or 'C' and once per second a timestamp will
92
 * appear.  Send a 'P' to get the satellite position once (GOES only.)
93
 *
94
 * Notes on the 468-DC receiver:
95
 *
96
 * Since the old east/west satellite locations are only historical, you can't
97
 * set your clock propagation delay settings correctly and still use
98
 * automatic mode. The manual says to use a compromise when setting the
99
 * switches. This results in significant errors. The solution; use fudge
100
 * time1 and time2 to incorporate corrections. If your clock is set for
101
 * 50 and it should be 58 for using the west and 46 for using the east,
102
 * use the line
103
 *
104
 * fudge 127.127.5.0 time1 +0.008 time2 -0.004
105
 *
106
 * This corrects the 4 milliseconds advance and 8 milliseconds retard
107
 * needed. The software will ask the clock which satellite it sees.
108
 *
109
 * Notes on the TrueTime TimeLink TL-3 WWV TOD receiver:
110
 * 
111
 * This clock may be polled, or send one timecode per second.
112
 * That mode may be toggled via the front panel ("C" mode), or controlled
113
 * from the RS-232 port.  Send the receiver "ST1" to turn it on, and
114
 * "ST0" to turn it off.  Send "QV" to get the firmware revision (useful
115
 * for identifying this model.)
116
 * 
117
 * Note that it can take several polling cycles, especially if the receiver
118
 * was in the continuous timecode mode.  (It can be slow to leave that mode.)
119
 * 
120
 * ntp.conf parameters:
121
 * time1   - offset applied to samples when reading WEST satellite (default = 0)
122
 * time2   - offset applied to samples when reading EAST satellite (default = 0)
123
 * stratum - stratum to assign to this clock (default = 0)
124
 * refid   - refid assigned to this clock (default = "TRUE", see below)
125
 * flag1   - will silence the clock side of ntpd, just reading the clock
126
 *       without trying to write to it.  (default = 0)
127
 * flag2   - generate a debug file /tmp/true%d.
128
 * flag3   - enable ppsclock streams module
129
 * flag4   - use the PCL-720 (BSD/OS only)
130
 */
131
132
133
/*
134
 * Definitions
135
 */
136
#define DEVICE    "/dev/true%d"
137
0
#define SPEED232  B9600  /* 9600 baud */
138
139
/*
140
 * Radio interface parameters
141
 */
142
0
#define PRECISION (-10)  /* precision assumed (about 1 ms) */
143
0
#define REFID   "TRUE"  /* reference id */
144
0
#define DESCRIPTION "Kinemetrics/TrueTime Receiver"
145
146
/*
147
 * Tags which station (satellite) we see
148
 */
149
0
#define GOES_WEST 0  /* Default to WEST satellite and apply time1 */
150
0
#define GOES_EAST 1  /* until you discover otherwise */
151
152
/*
153
 * used by the state machine
154
 */
155
enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
156
     e_TL3, e_Poll, e_Location, e_TS, e_Max};
157
const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
158
      "TL3", "Poll", "Location", "TS"};
159
0
#define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
160
161
enum true_state {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
162
     s_InqTL3, s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
163
const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
164
      "InqTL3", "Init", "F18", "F50", "Start", "Auto"};
165
0
#define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
166
167
enum true_type  {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_tl3, t_Max};
168
const char *types[] = {"unknown", "goes", "tm", "tcu", "omega", "tl3"};
169
0
#define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
170
171
/*
172
 * unit control structure
173
 */
174
struct true_unit {
175
  unsigned int  pollcnt;  /* poll message counter */
176
  unsigned int  station;  /* which station we are on */
177
  unsigned int  polled;   /* Hand in a time sample? */
178
  enum true_state state;    /* state machine */
179
  enum true_type  type;   /* what kind of clock is it? */
180
  int   unit;   /* save an extra copy of this */
181
  FILE    *debug;   /* debug logging file */
182
#ifdef CLOCK_PPS720
183
  int   pcl720init; /* init flag for PCL 720 */
184
#endif
185
};
186
187
/*
188
 * Function prototypes
189
 */
190
static  int true_start  (int, struct peer *);
191
static  void  true_shutdown (int, struct peer *);
192
static  void  true_receive  (struct recvbuf *);
193
static  void  true_poll (int, struct peer *);
194
static  void  true_send (struct peer *, const char *);
195
static  void  true_doevent  (struct peer *, enum true_event);
196
197
#ifdef CLOCK_PPS720
198
static  u_long  true_sample720  (void);
199
#endif
200
201
/*
202
 * Transfer vector
203
 */
204
struct  refclock refclock_true = {
205
  true_start,   /* start up driver */
206
  true_shutdown,    /* shut down driver */
207
  true_poll,    /* transmit poll message */
208
  noentry,    /* not used (old true_control) */
209
  noentry,    /* initialize driver (not used) */
210
  noentry,    /* not used (old true_buginfo) */
211
  NOFLAGS     /* not used */
212
};
213
214
215
#if !defined(__STDC__)
216
# define true_debug (void)
217
#else
218
NTP_PRINTF(2, 3)
219
static void
220
true_debug(struct peer *peer, const char *fmt, ...)
221
0
{
222
0
  va_list ap;
223
0
  int want_debugging, now_debugging;
224
0
  struct refclockproc *pp;
225
0
  struct true_unit *up;
226
227
0
  va_start(ap, fmt);
228
0
  pp = peer->procptr;
229
0
  up = pp->unitptr;
230
231
0
  want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
232
0
  now_debugging = (up->debug != NULL);
233
0
  if (want_debugging != now_debugging)
234
0
  {
235
0
    if (want_debugging) {
236
0
      char filename[40];
237
0
      int fd;
238
239
0
      snprintf(filename, sizeof(filename),
240
0
         "/tmp/true%d.debug", up->unit);
241
0
      fd = open(filename, O_CREAT | O_WRONLY | O_EXCL,
242
0
          0600);
243
0
      if (fd >= 0 && (up->debug = fdopen(fd, "w"))) {
244
0
#ifdef HAVE_SETVBUF
245
0
        static char buf[BUFSIZ];
246
247
0
        setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
248
#else
249
        setlinebuf(up->debug);
250
#endif
251
0
      }
252
0
    } else {
253
0
      fclose(up->debug);
254
0
      up->debug = NULL;
255
0
    }
256
0
  }
257
258
0
  if (up->debug) {
259
0
    fprintf(up->debug, "true%d: ", up->unit);
260
0
    vfprintf(up->debug, fmt, ap);
261
0
  }
262
0
  va_end(ap);
263
0
}
264
#endif /*STDC*/
265
266
/*
267
 * true_start - open the devices and initialize data for processing
268
 */
269
static int
270
true_start(
271
  int unit,
272
  struct peer *peer
273
  )
274
0
{
275
0
  register struct true_unit *up;
276
0
  struct refclockproc *pp;
277
0
  char device[40];
278
0
  int fd;
279
280
  /*
281
   * Open serial port
282
   */
283
0
  snprintf(device, sizeof(device), DEVICE, unit);
284
0
  fd = refclock_open(device, SPEED232, LDISC_CLK);
285
0
  if (fd <= 0)
286
0
    return 0;
287
288
  /*
289
   * Allocate and initialize unit structure
290
   */
291
0
  up = emalloc_zero(sizeof(*up));
292
0
  pp = peer->procptr;
293
0
  pp->io.clock_recv = true_receive;
294
0
  pp->io.srcclock = peer;
295
0
  pp->io.datalen = 0;
296
0
  pp->io.fd = fd;
297
0
  if (!io_addclock(&pp->io)) {
298
0
    close(fd);
299
0
    pp->io.fd = -1;
300
0
    free(up);
301
0
    return (0);
302
0
  }
303
0
  pp->unitptr = up;
304
305
  /*
306
   * Initialize miscellaneous variables
307
   */
308
0
  peer->precision = PRECISION;
309
0
  pp->clockdesc = DESCRIPTION;
310
0
  memcpy(&pp->refid, REFID, 4);
311
0
  up->pollcnt = 2;
312
0
  up->type = t_unknown;
313
0
  up->state = s_Base;
314
315
  /*
316
   * Send a CTRL-C character at the start,
317
   * just in case the clock is already
318
   * sending timecodes
319
   */
320
0
  true_send(peer, "\03\r");
321
  
322
0
  true_doevent(peer, e_Init);
323
324
0
  return (1);
325
0
}
326
327
328
/*
329
 * true_shutdown - shut down the clock
330
 */
331
static void
332
true_shutdown(
333
  int unit,
334
  struct peer *peer
335
  )
336
0
{
337
0
  register struct true_unit *up;
338
0
  struct refclockproc *pp;
339
340
0
  pp = peer->procptr;
341
0
  up = pp->unitptr;
342
0
  if (pp->io.fd != -1)
343
0
    io_closeclock(&pp->io);
344
0
  if (up != NULL)
345
0
    free(up);
346
0
}
347
348
349
/*
350
 * true_receive - receive data from the serial interface on a clock
351
 */
352
static void
353
true_receive(
354
  struct recvbuf *rbufp
355
  )
356
0
{
357
0
  register struct true_unit *up;
358
0
  struct refclockproc *pp;
359
0
  struct peer *peer;
360
0
  u_short new_station;
361
0
  char synced;
362
0
  int i;
363
0
  int lat, lon, off;  /* GOES Satellite position */
364
  /* These variables hold data until we decide to keep it */
365
0
  char  rd_lastcode[BMAX];
366
0
  l_fp  rd_tmp;
367
0
  u_short rd_lencode;
368
369
  /*
370
   * Get the clock this applies to and pointers to the data.
371
   */
372
0
  peer = rbufp->recv_peer;
373
0
  pp = peer->procptr;
374
0
  up = pp->unitptr;
375
376
  /*
377
   * Read clock output.  Automatically handles STREAMS, CLKLDISC.
378
   */
379
0
  rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
380
0
  rd_lastcode[rd_lencode] = '\0';
381
382
  /*
383
   * There is a case where <cr><lf> generates 2 timestamps.
384
   */
385
0
  if (rd_lencode == 0)
386
0
    return;
387
0
  pp->lencode = rd_lencode;
388
0
  strlcpy(pp->a_lastcode, rd_lastcode, sizeof(pp->a_lastcode));
389
0
  pp->lastrec = rd_tmp;
390
0
  true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode,
391
0
       pp->lencode);
392
393
0
  up->pollcnt = 2;
394
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
395
396
  /*
397
   * We get down to business, check the timecode format and decode
398
   * its contents. This code decodes a multitude of different
399
   * clock messages. Timecodes are processed if needed. All replies
400
   * will be run through the state machine to tweak driver options
401
   * and program the clock.
402
   */
403
404
  /*
405
   * Clock misunderstood our last command?
406
   */
407
0
  if (pp->a_lastcode[0] == '?' ||
408
0
      strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
409
0
    true_doevent(peer, e_Huh);
410
0
    return;
411
0
  }
412
413
  /*
414
   * Timecode: "nnnnn+nnn-nnn"
415
   * (from GOES clock when asked about satellite position)
416
   */
417
0
  if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
418
0
      (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
419
0
      sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
420
0
      ) {
421
0
    const char *label = "Botch!";
422
423
    /*
424
     * This is less than perfect.  Call the (satellite)
425
     * either EAST or WEST and adjust slop accodingly
426
     * Perfectionists would recalculate the exact delay
427
     * and adjust accordingly...
428
     */
429
0
    if (lon > 7000 && lon < 14000) {
430
0
      if (lon < 10000) {
431
0
        new_station = GOES_EAST;
432
0
        label = "EAST";
433
0
      } else {
434
0
        new_station = GOES_WEST;
435
0
        label = "WEST";
436
0
      }
437
        
438
0
      if (new_station != up->station) {
439
0
        double dtemp;
440
441
0
        dtemp = pp->fudgetime1;
442
0
        pp->fudgetime1 = pp->fudgetime2;
443
0
        pp->fudgetime2 = dtemp;
444
0
        up->station = new_station;
445
0
      }
446
0
    }
447
0
    else {
448
      /*refclock_report(peer, CEVNT_BADREPLY);*/
449
0
      label = "UNKNOWN";
450
0
    }
451
0
    true_debug(peer, "GOES: station %s\n", label);
452
0
    true_doevent(peer, e_Satellite);
453
0
    return;
454
0
  }
455
456
  /*
457
   * Timecode: "Fnn"
458
   * (from TM/TMD clock when it wants to tell us what it's up to.)
459
   */
460
0
  if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
461
0
    switch (i) {
462
0
    case 50:
463
0
      true_doevent(peer, e_F50);
464
0
      break;
465
0
    case 51:
466
0
      true_doevent(peer, e_F51);
467
0
      break;
468
0
    default:
469
0
      true_debug(peer, "got F%02d - ignoring\n", i);
470
0
      break;
471
0
    }
472
0
    return;
473
0
  }
474
475
        /*
476
         * Timecode: "VER xx.xx"
477
         * (from a TL3 when sent "QV", so id's it during initialization.)
478
         */
479
0
        if (pp->a_lastcode[0] == 'V' && pp->a_lastcode[1] == 'E' &&
480
0
            pp->a_lastcode[2] == 'R' && pp->a_lastcode[6] == '.') {
481
0
                true_doevent(peer, e_TL3);
482
0
                NLOG(NLOG_CLOCKSTATUS) {
483
0
                        msyslog(LOG_INFO, "TL3: %s", pp->a_lastcode);
484
0
                }
485
0
                return;
486
0
        }
487
488
  /*
489
   * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
490
   * (from a TM/TMD/XL clock during initialization.)
491
   */
492
0
  if (strncmp(pp->a_lastcode, " TRUETIME Mk III ", 17) == 0 ||
493
0
      strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
494
0
    true_doevent(peer, e_F18);
495
0
    NLOG(NLOG_CLOCKSTATUS) {
496
0
      msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
497
0
    }
498
0
    return;
499
0
  }
500
501
  /*
502
   * Timecode: "N03726428W12209421+000033"
503
   *      1    2
504
   * index      0123456789012345678901234
505
   * (from a TCU during initialization)
506
   */
507
0
  if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
508
0
      (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
509
0
      pp->a_lastcode[18] == '+') {
510
0
    true_doevent(peer, e_Location);
511
0
    NLOG(NLOG_CLOCKSTATUS) {
512
0
      msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
513
0
    }
514
0
    return;
515
0
  }
516
  /*
517
   * Timecode: "ddd:hh:mm:ssQ"
518
   *      1    2
519
   * index      0123456789012345678901234
520
   * (from all clocks supported by this driver.)
521
   */
522
0
  if (pp->a_lastcode[3] == ':' &&
523
0
      pp->a_lastcode[6] == ':' &&
524
0
      pp->a_lastcode[9] == ':' &&
525
0
      sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
526
0
       &pp->day, &pp->hour, &pp->minute,
527
0
       &pp->second, &synced) == 5) {
528
529
    /*
530
     * Adjust the synchronize indicator according to timecode
531
     * say were OK, and then say not if we really are not OK
532
     */
533
0
    if (synced == '>' || synced == '#' || synced == '?'
534
0
        || synced == 'X')
535
0
      pp->leap = LEAP_NOTINSYNC;
536
0
    else
537
0
      pp->leap = LEAP_NOWARNING;
538
539
0
    true_doevent(peer, e_TS);
540
541
#ifdef CLOCK_PPS720
542
    /* If it's taken more than 65ms to get here, we'll lose. */
543
    if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) {
544
      l_fp   off;
545
546
#ifdef CLOCK_ATOM
547
      /*
548
       * find out what time it really is. Include
549
       * the count from the PCL720
550
       */
551
      if (!clocktime(pp->day, pp->hour, pp->minute, 
552
               pp->second, GMT, pp->lastrec.l_ui, 
553
               &pp->yearstart, &off.l_ui)) {
554
        refclock_report(peer, CEVNT_BADTIME);
555
        return;
556
      }
557
      off.l_uf = 0;
558
#endif
559
560
      pp->usec = true_sample720();
561
#ifdef CLOCK_ATOM
562
      TVUTOTSF(pp->usec, off.l_uf);
563
#endif
564
565
      /*
566
       * Stomp all over the timestamp that was pulled out
567
       * of the input stream. It's irrelevant since we've
568
       * adjusted the input time to reflect now (via pp->usec)
569
       * rather than when the data was collected.
570
       */
571
      get_systime(&pp->lastrec);
572
#ifdef CLOCK_ATOM
573
      /*
574
       * Create a true offset for feeding to pps_sample()
575
       */
576
      L_SUB(&off, &pp->lastrec);
577
578
      pps_sample(peer, &off);
579
#endif
580
      true_debug(peer, "true_sample720: %luus\n", pp->usec);
581
    }
582
#endif
583
584
    /*
585
     * The clock will blurt a timecode every second but we only
586
     * want one when polled.  If we havn't been polled, bail out.
587
     */
588
0
    if (!up->polled)
589
0
      return;
590
591
                /* We only call doevent if additional things need be done
592
                 * at poll interval.  Currently, its only for GOES.  We also
593
                 * call it for clock unknown so that it gets logged.
594
                 */
595
0
                if (up->type == t_goes || up->type == t_unknown)
596
0
                    true_doevent(peer, e_Poll);
597
598
0
    if (!refclock_process(pp)) {
599
0
      refclock_report(peer, CEVNT_BADTIME);
600
0
      return;
601
0
    }
602
    /*
603
     * If clock is good we send a NOMINAL message so that
604
     * any previous BAD messages are nullified
605
     */
606
0
    pp->lastref = pp->lastrec;
607
0
    refclock_receive(peer);
608
0
    refclock_report(peer, CEVNT_NOMINAL);
609
610
    /*
611
     * We have succedded in answering the poll.
612
     * Turn off the flag and return
613
     */
614
0
    up->polled = 0;
615
616
0
    return;
617
0
  }
618
619
  /*
620
   * No match to known timecodes, report failure and return
621
   */
622
0
  refclock_report(peer, CEVNT_BADREPLY);
623
0
  return;
624
0
}
625
626
627
/*
628
 * true_send - time to send the clock a signal to cough up a time sample
629
 */
630
static void
631
true_send(
632
  struct peer *peer,
633
  const char *cmd
634
  )
635
0
{
636
0
  struct refclockproc *pp;
637
638
0
  pp = peer->procptr;
639
0
  if (!(pp->sloppyclockflag & CLK_FLAG1)) {
640
0
    size_t len = strlen(cmd);
641
642
0
    true_debug(peer, "Send '%s'\n", cmd);
643
0
    if (write(pp->io.fd, cmd, len) != (ssize_t)len)
644
0
      refclock_report(peer, CEVNT_FAULT);
645
0
    else
646
0
      pp->polls++;
647
0
  }
648
0
}
649
650
651
/*
652
 * state machine for initializing and controlling a clock
653
 */
654
static void
655
true_doevent(
656
  struct peer *peer,
657
  enum true_event event
658
  )
659
0
{
660
0
  struct true_unit *up;
661
0
  struct refclockproc *pp;
662
663
0
  pp = peer->procptr;
664
0
  up = pp->unitptr;
665
0
  if (event != e_TS) {
666
0
    NLOG(NLOG_CLOCKSTATUS) {
667
0
      msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
668
0
        typeStr(up->type),
669
0
        stateStr(up->state),
670
0
        eventStr(event));
671
0
    }
672
0
  }
673
0
  true_debug(peer, "clock %s, state %s, event %s\n",
674
0
       typeStr(up->type), stateStr(up->state), eventStr(event));
675
0
  switch (up->type) {
676
0
  case t_goes:
677
0
    switch (event) {
678
0
    case e_Init:  /* FALLTHROUGH */
679
0
    case e_Satellite:
680
      /*
681
       * Switch back to on-second time codes and return.
682
       */
683
0
      true_send(peer, "C");
684
0
      up->state = s_Start;
685
0
      break;
686
0
    case e_Poll:
687
      /*
688
       * After each poll, check the station (satellite).
689
       */
690
0
      true_send(peer, "P");
691
      /* No state change needed. */
692
0
      break;
693
0
    default:
694
0
      break;
695
0
    }
696
    /* FALLTHROUGH */
697
0
  case t_omega:
698
0
    switch (event) {
699
0
    case e_Init:
700
0
      true_send(peer, "C");
701
0
      up->state = s_Start;
702
0
      break;
703
0
    case e_TS:
704
0
      if (up->state != s_Start && up->state != s_Auto) {
705
0
        true_send(peer, "\03\r");
706
0
        break;
707
0
      }
708
0
      up->state = s_Auto;
709
0
      break;
710
0
    default:
711
0
      break;
712
0
    }
713
0
    break;
714
0
  case t_tm:
715
0
    switch (event) {
716
0
    case e_Init:
717
0
      true_send(peer, "F18\r");
718
0
      up->state = s_Init;
719
0
      break;
720
0
    case e_F18:
721
0
      true_send(peer, "F50\r");
722
                        /*
723
                         * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
724
                         * (from a TM/TMD/XL clock during initialization.)
725
                         */
726
0
                        if ( strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
727
0
                            strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
728
0
                                true_doevent(peer, e_F18);
729
0
                                NLOG(NLOG_CLOCKSTATUS) {
730
0
                                    msyslog(LOG_INFO, "TM/TMD/XL: %s", 
731
0
                                            pp->a_lastcode);
732
0
                                }
733
0
                                return;
734
0
                        }
735
0
      up->state = s_F18;
736
0
      break;
737
0
    case e_F50:
738
0
      true_send(peer, "F51\r");
739
0
      up->state = s_F50;
740
0
      break;
741
0
    case e_F51:
742
0
      true_send(peer, "F08\r");
743
0
      up->state = s_Start;
744
0
      break;
745
0
    case e_TS:
746
0
      if (up->state != s_Start && up->state != s_Auto) {
747
0
        true_send(peer, "\03\r");
748
0
        break;
749
0
      }
750
0
      up->state = s_Auto;
751
0
      break;
752
0
    default:
753
0
      break;
754
0
    }
755
0
    break;
756
0
  case t_tcu:
757
0
    switch (event) {
758
0
    case e_Init:
759
0
      true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */
760
0
      true_send(peer, "TSU\r"); /* UTC, not GPS. */
761
0
      true_send(peer, "AU\r");  /* Auto Timestamps. */
762
0
      up->state = s_Start;
763
0
      break;
764
0
    case e_TS:
765
0
      if (up->state != s_Start && up->state != s_Auto) {
766
0
        true_send(peer, "\03\r");
767
0
        break;
768
0
      }
769
0
      up->state = s_Auto;
770
0
      break;
771
0
    default:
772
0
      break;
773
0
    }
774
0
    break;
775
0
  case t_tl3:
776
0
                switch (event) {
777
0
                    case e_Init:
778
0
                        true_send(peer, "ST1"); /* Turn on continuous stream */
779
0
                        break;
780
0
                    case e_TS:
781
0
                        up->state = s_Auto;
782
0
                        break;
783
0
                    default:
784
0
                        break;
785
0
                }
786
0
                break;
787
0
  case t_unknown:
788
0
               if (event == e_Poll)
789
0
                   break;
790
0
    switch (up->state) {
791
0
    case s_Base:
792
0
      if (event != e_Init)
793
0
          abort();
794
0
      true_send(peer, "P\r");
795
0
      up->state = s_InqGOES;
796
0
      break;
797
0
    case s_InqGOES:
798
0
      switch (event) {
799
0
      case e_Satellite:
800
0
        up->type = t_goes;
801
0
        true_doevent(peer, e_Init);
802
0
        break;
803
0
      case e_Init:  /*FALLTHROUGH*/
804
0
      case e_Huh:
805
0
      case e_TS:
806
0
                                true_send(peer, "ST0"); /* turn off TL3 auto */
807
0
                                sleep(1);               /* wait for it */
808
0
                                up->state = s_InqTL3;
809
0
                                true_send(peer, "QV");  /* see if its a TL3 */
810
0
                                break;
811
0
                            default:
812
0
                                abort();
813
0
                        }
814
0
                        break;
815
0
                    case s_InqTL3:
816
0
                        switch (event) {
817
0
                            case e_TL3:
818
0
                                up->type = t_tl3;
819
0
                                up->state = s_Auto;     /* Inq side-effect. */
820
0
                                true_send(peer, "ST1"); /* Turn on 1/sec data */
821
0
                                break;
822
0
                            case e_Init:        /*FALLTHROUGH*/
823
0
                            case e_Huh:
824
0
        up->state = s_InqOmega;
825
0
        true_send(peer, "C\r");
826
0
        break;
827
0
                            case e_TS:
828
0
                                 up->type = t_tl3;    /* Already sending data */
829
0
                                 up->state = s_Auto;
830
0
                                 break;
831
0
          default:
832
0
                                msyslog(LOG_INFO, 
833
0
                                        "TRUE: TL3 init fellthrough! (%d)", event);
834
0
                                break; 
835
0
      }
836
0
      break;
837
0
    case s_InqOmega:
838
0
      switch (event) {
839
0
      case e_TS:
840
0
        up->type = t_omega;
841
0
        up->state = s_Auto; /* Inq side-effect. */
842
0
        break;
843
0
      case e_Init:  /*FALLTHROUGH*/
844
0
      case e_Huh:
845
0
        up->state = s_InqTM;
846
0
        true_send(peer, "F18\r");
847
0
        break;
848
0
      default:
849
0
        abort();
850
0
      }
851
0
      break;
852
0
    case s_InqTM:
853
0
      switch (event) {
854
0
      case e_F18:
855
0
        up->type = t_tm;
856
0
        true_doevent(peer, e_Init);
857
0
        break;
858
0
      case e_Init:  /*FALLTHROUGH*/
859
0
      case e_Huh:
860
0
        true_send(peer, "PO\r");
861
0
        up->state = s_InqTCU;
862
0
        break;
863
0
      default:
864
0
                                msyslog(LOG_INFO, 
865
0
                                        "TRUE: TM/TMD init fellthrough!");
866
0
              break;
867
0
      }
868
0
      break;
869
0
    case s_InqTCU:
870
0
      switch (event) {
871
0
      case e_Location:
872
0
        up->type = t_tcu;
873
0
        true_doevent(peer, e_Init);
874
0
        break;
875
0
      case e_Init:  /*FALLTHROUGH*/
876
0
      case e_Huh:
877
0
        up->state = s_Base;
878
0
        sleep(1); /* XXX */
879
0
        break;
880
0
      default:
881
0
                                msyslog(LOG_INFO, 
882
0
                                        "TRUE: TCU init fellthrough!");
883
0
                                break;
884
0
      }
885
0
      break;
886
      /*
887
       * An expedient hack to prevent lint complaints,
888
       * these don't actually need to be used here...
889
       */
890
0
    case s_Init:
891
0
    case s_F18:
892
0
    case s_F50:
893
0
    case s_Start:
894
0
    case s_Auto:
895
0
    case s_Max:
896
0
      msyslog(LOG_INFO, "TRUE: state %s is unexpected!",
897
0
        stateStr(up->state));
898
0
    }
899
0
    break;
900
0
  default:
901
0
                msyslog(LOG_INFO, "TRUE: cannot identify refclock!");
902
0
    abort();    
903
    /* NOTREACHED */
904
0
  }
905
906
#ifdef CLOCK_PPS720
907
  if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) {
908
    /* Make counter trigger on gate0, count down from 65535. */
909
    pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535);
910
    /*
911
     * (These constants are OK since
912
     * they represent hardware maximums.)
913
     */
914
    NLOG(NLOG_CLOCKINFO) {
915
      msyslog(LOG_NOTICE, "PCL-720 initialized");
916
    }
917
    up->pcl720init++;
918
  }
919
#endif
920
921
922
0
}
923
924
/*
925
 * true_poll - called by the transmit procedure
926
 */
927
static void
928
true_poll(
929
  int unit,
930
  struct peer *peer
931
  )
932
0
{
933
0
  struct true_unit *up;
934
0
  struct refclockproc *pp;
935
936
  /*
937
   * You don't need to poll this clock.  It puts out timecodes
938
   * once per second.  If asked for a timestamp, take note.
939
   * The next time a timecode comes in, it will be fed back.
940
   */
941
0
  pp = peer->procptr;
942
0
  up = pp->unitptr;
943
0
  if (up->pollcnt > 0) {
944
0
    up->pollcnt--;
945
0
  } else {
946
0
    true_doevent(peer, e_Init);
947
0
    refclock_report(peer, CEVNT_TIMEOUT);
948
0
  }
949
950
  /*
951
   * polled every 64 seconds. Ask true_receive to hand in a
952
   * timestamp.
953
   */
954
0
  up->polled = 1;
955
0
  pp->polls++;
956
0
}
957
958
#ifdef CLOCK_PPS720
959
/*
960
 * true_sample720 - sample the PCL-720
961
 */
962
static u_long
963
true_sample720(void)
964
{
965
  unsigned long f;
966
967
  /* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3.
968
   * If it is not being held low now, we did not get called
969
   * within 65535us.
970
   */
971
  if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) {
972
    NLOG(NLOG_CLOCKINFO) {
973
      msyslog(LOG_NOTICE, "PCL-720 out of synch");
974
    }
975
    return (0);
976
  }
977
  f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR));
978
#ifdef PPS720_DEBUG
979
  msyslog(LOG_DEBUG, "PCL-720: %luus", f);
980
#endif
981
  return (f);
982
}
983
#endif
984
985
#else
986
int refclock_true_bs;
987
#endif /* REFCLOCK */