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