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