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 #define SPEED232 B9600 /* 9600 baud */
138
139 /*
140 * Radio interface parameters
141 */
142 #define PRECISION (-10) /* precision assumed (about 1 ms) */
143 #define REFID "TRUE" /* reference id */
144 #define DESCRIPTION "Kinemetrics/TrueTime Receiver"
145
146 /*
147 * Tags which station (satellite) we see
148 */
149 #define GOES_WEST 0 /* Default to WEST satellite and apply time1 */
150 #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 #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 #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 #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
true_debug(struct peer * peer,const char * fmt,...)220 true_debug(struct peer *peer, const char *fmt, ...)
221 {
222 va_list ap;
223 int want_debugging, now_debugging;
224 struct refclockproc *pp;
225 struct true_unit *up;
226
227 va_start(ap, fmt);
228 pp = peer->procptr;
229 up = pp->unitptr;
230
231 want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
232 now_debugging = (up->debug != NULL);
233 if (want_debugging != now_debugging)
234 {
235 if (want_debugging) {
236 char filename[40];
237 int fd;
238
239 snprintf(filename, sizeof(filename),
240 "/tmp/true%d.debug", up->unit);
241 fd = open(filename, O_CREAT | O_WRONLY | O_EXCL,
242 0600);
243 if (fd >= 0 && (up->debug = fdopen(fd, "w"))) {
244 #ifdef HAVE_SETVBUF
245 static char buf[BUFSIZ];
246
247 setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
248 #else
249 setlinebuf(up->debug);
250 #endif
251 }
252 } else {
253 fclose(up->debug);
254 up->debug = NULL;
255 }
256 }
257
258 if (up->debug) {
259 fprintf(up->debug, "true%d: ", up->unit);
260 vfprintf(up->debug, fmt, ap);
261 }
262 va_end(ap);
263 }
264 #endif /*STDC*/
265
266 /*
267 * true_start - open the devices and initialize data for processing
268 */
269 static int
true_start(int unit,struct peer * peer)270 true_start(
271 int unit,
272 struct peer *peer
273 )
274 {
275 register struct true_unit *up;
276 struct refclockproc *pp;
277 char device[40];
278 int fd;
279
280 /*
281 * Open serial port
282 */
283 snprintf(device, sizeof(device), DEVICE, unit);
284 fd = refclock_open(device, SPEED232, LDISC_CLK);
285 if (fd <= 0)
286 return 0;
287
288 /*
289 * Allocate and initialize unit structure
290 */
291 up = emalloc_zero(sizeof(*up));
292 pp = peer->procptr;
293 pp->io.clock_recv = true_receive;
294 pp->io.srcclock = peer;
295 pp->io.datalen = 0;
296 pp->io.fd = fd;
297 if (!io_addclock(&pp->io)) {
298 close(fd);
299 pp->io.fd = -1;
300 free(up);
301 return (0);
302 }
303 pp->unitptr = up;
304
305 /*
306 * Initialize miscellaneous variables
307 */
308 peer->precision = PRECISION;
309 pp->clockdesc = DESCRIPTION;
310 memcpy(&pp->refid, REFID, 4);
311 up->pollcnt = 2;
312 up->type = t_unknown;
313 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 true_send(peer, "\03\r");
321
322 true_doevent(peer, e_Init);
323
324 return (1);
325 }
326
327
328 /*
329 * true_shutdown - shut down the clock
330 */
331 static void
true_shutdown(int unit,struct peer * peer)332 true_shutdown(
333 int unit,
334 struct peer *peer
335 )
336 {
337 register struct true_unit *up;
338 struct refclockproc *pp;
339
340 pp = peer->procptr;
341 up = pp->unitptr;
342 if (pp->io.fd != -1)
343 io_closeclock(&pp->io);
344 if (up != NULL)
345 free(up);
346 }
347
348
349 /*
350 * true_receive - receive data from the serial interface on a clock
351 */
352 static void
true_receive(struct recvbuf * rbufp)353 true_receive(
354 struct recvbuf *rbufp
355 )
356 {
357 register struct true_unit *up;
358 struct refclockproc *pp;
359 struct peer *peer;
360 u_short new_station;
361 char synced;
362 int i;
363 int lat, lon, off; /* GOES Satellite position */
364 /* These variables hold data until we decide to keep it */
365 char rd_lastcode[BMAX];
366 l_fp rd_tmp;
367 u_short rd_lencode;
368
369 /*
370 * Get the clock this applies to and pointers to the data.
371 */
372 peer = rbufp->recv_peer;
373 pp = peer->procptr;
374 up = pp->unitptr;
375
376 /*
377 * Read clock output. Automatically handles STREAMS, CLKLDISC.
378 */
379 rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
380 rd_lastcode[rd_lencode] = '\0';
381
382 /*
383 * There is a case where <cr><lf> generates 2 timestamps.
384 */
385 if (rd_lencode == 0)
386 return;
387 pp->lencode = rd_lencode;
388 strlcpy(pp->a_lastcode, rd_lastcode, sizeof(pp->a_lastcode));
389 pp->lastrec = rd_tmp;
390 true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode,
391 pp->lencode);
392
393 up->pollcnt = 2;
394 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 if (pp->a_lastcode[0] == '?' ||
408 strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
409 true_doevent(peer, e_Huh);
410 return;
411 }
412
413 /*
414 * Timecode: "nnnnn+nnn-nnn"
415 * (from GOES clock when asked about satellite position)
416 */
417 if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
418 (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
419 sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
420 ) {
421 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 if (lon > 7000 && lon < 14000) {
430 if (lon < 10000) {
431 new_station = GOES_EAST;
432 label = "EAST";
433 } else {
434 new_station = GOES_WEST;
435 label = "WEST";
436 }
437
438 if (new_station != up->station) {
439 double dtemp;
440
441 dtemp = pp->fudgetime1;
442 pp->fudgetime1 = pp->fudgetime2;
443 pp->fudgetime2 = dtemp;
444 up->station = new_station;
445 }
446 }
447 else {
448 /*refclock_report(peer, CEVNT_BADREPLY);*/
449 label = "UNKNOWN";
450 }
451 true_debug(peer, "GOES: station %s\n", label);
452 true_doevent(peer, e_Satellite);
453 return;
454 }
455
456 /*
457 * Timecode: "Fnn"
458 * (from TM/TMD clock when it wants to tell us what it's up to.)
459 */
460 if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
461 switch (i) {
462 case 50:
463 true_doevent(peer, e_F50);
464 break;
465 case 51:
466 true_doevent(peer, e_F51);
467 break;
468 default:
469 true_debug(peer, "got F%02d - ignoring\n", i);
470 break;
471 }
472 return;
473 }
474
475 /*
476 * Timecode: "VER xx.xx"
477 * (from a TL3 when sent "QV", so id's it during initialization.)
478 */
479 if (pp->a_lastcode[0] == 'V' && pp->a_lastcode[1] == 'E' &&
480 pp->a_lastcode[2] == 'R' && pp->a_lastcode[6] == '.') {
481 true_doevent(peer, e_TL3);
482 NLOG(NLOG_CLOCKSTATUS) {
483 msyslog(LOG_INFO, "TL3: %s", pp->a_lastcode);
484 }
485 return;
486 }
487
488 /*
489 * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
490 * (from a TM/TMD/XL clock during initialization.)
491 */
492 if (strncmp(pp->a_lastcode, " TRUETIME Mk III ", 17) == 0 ||
493 strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
494 true_doevent(peer, e_F18);
495 NLOG(NLOG_CLOCKSTATUS) {
496 msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
497 }
498 return;
499 }
500
501 /*
502 * Timecode: "N03726428W12209421+000033"
503 * 1 2
504 * index 0123456789012345678901234
505 * (from a TCU during initialization)
506 */
507 if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
508 (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
509 pp->a_lastcode[18] == '+') {
510 true_doevent(peer, e_Location);
511 NLOG(NLOG_CLOCKSTATUS) {
512 msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
513 }
514 return;
515 }
516 /*
517 * Timecode: "ddd:hh:mm:ssQ"
518 * 1 2
519 * index 0123456789012345678901234
520 * (from all clocks supported by this driver.)
521 */
522 if (pp->a_lastcode[3] == ':' &&
523 pp->a_lastcode[6] == ':' &&
524 pp->a_lastcode[9] == ':' &&
525 sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
526 &pp->day, &pp->hour, &pp->minute,
527 &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 if (synced == '>' || synced == '#' || synced == '?'
534 || synced == 'X')
535 pp->leap = LEAP_NOTINSYNC;
536 else
537 pp->leap = LEAP_NOWARNING;
538
539 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 if (!up->polled)
589 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 if (up->type == t_goes || up->type == t_unknown)
596 true_doevent(peer, e_Poll);
597
598 if (!refclock_process(pp)) {
599 refclock_report(peer, CEVNT_BADTIME);
600 return;
601 }
602 /*
603 * If clock is good we send a NOMINAL message so that
604 * any previous BAD messages are nullified
605 */
606 pp->lastref = pp->lastrec;
607 refclock_receive(peer);
608 refclock_report(peer, CEVNT_NOMINAL);
609
610 /*
611 * We have succedded in answering the poll.
612 * Turn off the flag and return
613 */
614 up->polled = 0;
615
616 return;
617 }
618
619 /*
620 * No match to known timecodes, report failure and return
621 */
622 refclock_report(peer, CEVNT_BADREPLY);
623 return;
624 }
625
626
627 /*
628 * true_send - time to send the clock a signal to cough up a time sample
629 */
630 static void
true_send(struct peer * peer,const char * cmd)631 true_send(
632 struct peer *peer,
633 const char *cmd
634 )
635 {
636 struct refclockproc *pp;
637
638 pp = peer->procptr;
639 if (!(pp->sloppyclockflag & CLK_FLAG1)) {
640 size_t len = strlen(cmd);
641
642 true_debug(peer, "Send '%s'\n", cmd);
643 if (write(pp->io.fd, cmd, len) != (ssize_t)len)
644 refclock_report(peer, CEVNT_FAULT);
645 else
646 pp->polls++;
647 }
648 }
649
650
651 /*
652 * state machine for initializing and controlling a clock
653 */
654 static void
true_doevent(struct peer * peer,enum true_event event)655 true_doevent(
656 struct peer *peer,
657 enum true_event event
658 )
659 {
660 struct true_unit *up;
661 struct refclockproc *pp;
662
663 pp = peer->procptr;
664 up = pp->unitptr;
665 if (event != e_TS) {
666 NLOG(NLOG_CLOCKSTATUS) {
667 msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
668 typeStr(up->type),
669 stateStr(up->state),
670 eventStr(event));
671 }
672 }
673 true_debug(peer, "clock %s, state %s, event %s\n",
674 typeStr(up->type), stateStr(up->state), eventStr(event));
675 switch (up->type) {
676 case t_goes:
677 switch (event) {
678 case e_Init: /* FALLTHROUGH */
679 case e_Satellite:
680 /*
681 * Switch back to on-second time codes and return.
682 */
683 true_send(peer, "C");
684 up->state = s_Start;
685 break;
686 case e_Poll:
687 /*
688 * After each poll, check the station (satellite).
689 */
690 true_send(peer, "P");
691 /* No state change needed. */
692 break;
693 default:
694 break;
695 }
696 /* FALLTHROUGH */
697 case t_omega:
698 switch (event) {
699 case e_Init:
700 true_send(peer, "C");
701 up->state = s_Start;
702 break;
703 case e_TS:
704 if (up->state != s_Start && up->state != s_Auto) {
705 true_send(peer, "\03\r");
706 break;
707 }
708 up->state = s_Auto;
709 break;
710 default:
711 break;
712 }
713 break;
714 case t_tm:
715 switch (event) {
716 case e_Init:
717 true_send(peer, "F18\r");
718 up->state = s_Init;
719 break;
720 case e_F18:
721 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 if ( strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
727 strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
728 true_doevent(peer, e_F18);
729 NLOG(NLOG_CLOCKSTATUS) {
730 msyslog(LOG_INFO, "TM/TMD/XL: %s",
731 pp->a_lastcode);
732 }
733 return;
734 }
735 up->state = s_F18;
736 break;
737 case e_F50:
738 true_send(peer, "F51\r");
739 up->state = s_F50;
740 break;
741 case e_F51:
742 true_send(peer, "F08\r");
743 up->state = s_Start;
744 break;
745 case e_TS:
746 if (up->state != s_Start && up->state != s_Auto) {
747 true_send(peer, "\03\r");
748 break;
749 }
750 up->state = s_Auto;
751 break;
752 default:
753 break;
754 }
755 break;
756 case t_tcu:
757 switch (event) {
758 case e_Init:
759 true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */
760 true_send(peer, "TSU\r"); /* UTC, not GPS. */
761 true_send(peer, "AU\r"); /* Auto Timestamps. */
762 up->state = s_Start;
763 break;
764 case e_TS:
765 if (up->state != s_Start && up->state != s_Auto) {
766 true_send(peer, "\03\r");
767 break;
768 }
769 up->state = s_Auto;
770 break;
771 default:
772 break;
773 }
774 break;
775 case t_tl3:
776 switch (event) {
777 case e_Init:
778 true_send(peer, "ST1"); /* Turn on continuous stream */
779 break;
780 case e_TS:
781 up->state = s_Auto;
782 break;
783 default:
784 break;
785 }
786 break;
787 case t_unknown:
788 if (event == e_Poll)
789 break;
790 switch (up->state) {
791 case s_Base:
792 if (event != e_Init)
793 abort();
794 true_send(peer, "P\r");
795 up->state = s_InqGOES;
796 break;
797 case s_InqGOES:
798 switch (event) {
799 case e_Satellite:
800 up->type = t_goes;
801 true_doevent(peer, e_Init);
802 break;
803 case e_Init: /*FALLTHROUGH*/
804 case e_Huh:
805 case e_TS:
806 true_send(peer, "ST0"); /* turn off TL3 auto */
807 sleep(1); /* wait for it */
808 up->state = s_InqTL3;
809 true_send(peer, "QV"); /* see if its a TL3 */
810 break;
811 default:
812 abort();
813 }
814 break;
815 case s_InqTL3:
816 switch (event) {
817 case e_TL3:
818 up->type = t_tl3;
819 up->state = s_Auto; /* Inq side-effect. */
820 true_send(peer, "ST1"); /* Turn on 1/sec data */
821 break;
822 case e_Init: /*FALLTHROUGH*/
823 case e_Huh:
824 up->state = s_InqOmega;
825 true_send(peer, "C\r");
826 break;
827 case e_TS:
828 up->type = t_tl3; /* Already sending data */
829 up->state = s_Auto;
830 break;
831 default:
832 msyslog(LOG_INFO,
833 "TRUE: TL3 init fellthrough! (%d)", event);
834 break;
835 }
836 break;
837 case s_InqOmega:
838 switch (event) {
839 case e_TS:
840 up->type = t_omega;
841 up->state = s_Auto; /* Inq side-effect. */
842 break;
843 case e_Init: /*FALLTHROUGH*/
844 case e_Huh:
845 up->state = s_InqTM;
846 true_send(peer, "F18\r");
847 break;
848 default:
849 abort();
850 }
851 break;
852 case s_InqTM:
853 switch (event) {
854 case e_F18:
855 up->type = t_tm;
856 true_doevent(peer, e_Init);
857 break;
858 case e_Init: /*FALLTHROUGH*/
859 case e_Huh:
860 true_send(peer, "PO\r");
861 up->state = s_InqTCU;
862 break;
863 default:
864 msyslog(LOG_INFO,
865 "TRUE: TM/TMD init fellthrough!");
866 break;
867 }
868 break;
869 case s_InqTCU:
870 switch (event) {
871 case e_Location:
872 up->type = t_tcu;
873 true_doevent(peer, e_Init);
874 break;
875 case e_Init: /*FALLTHROUGH*/
876 case e_Huh:
877 up->state = s_Base;
878 sleep(1); /* XXX */
879 break;
880 default:
881 msyslog(LOG_INFO,
882 "TRUE: TCU init fellthrough!");
883 break;
884 }
885 break;
886 /*
887 * An expedient hack to prevent lint complaints,
888 * these don't actually need to be used here...
889 */
890 case s_Init:
891 case s_F18:
892 case s_F50:
893 case s_Start:
894 case s_Auto:
895 case s_Max:
896 msyslog(LOG_INFO, "TRUE: state %s is unexpected!",
897 stateStr(up->state));
898 }
899 break;
900 default:
901 msyslog(LOG_INFO, "TRUE: cannot identify refclock!");
902 abort();
903 /* NOTREACHED */
904 }
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 }
923
924 /*
925 * true_poll - called by the transmit procedure
926 */
927 static void
true_poll(int unit,struct peer * peer)928 true_poll(
929 int unit,
930 struct peer *peer
931 )
932 {
933 struct true_unit *up;
934 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 pp = peer->procptr;
942 up = pp->unitptr;
943 if (up->pollcnt > 0) {
944 up->pollcnt--;
945 } else {
946 true_doevent(peer, e_Init);
947 refclock_report(peer, CEVNT_TIMEOUT);
948 }
949
950 /*
951 * polled every 64 seconds. Ask true_receive to hand in a
952 * timestamp.
953 */
954 up->polled = 1;
955 pp->polls++;
956 }
957
958 #ifdef CLOCK_PPS720
959 /*
960 * true_sample720 - sample the PCL-720
961 */
962 static u_long
true_sample720(void)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 */
988