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