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