]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpd/refclock_true.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / ntpd / refclock_true.c
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  */
135 enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
136                  e_Poll, e_Location, e_TS, e_Max};
137 const 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
141 enum 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};
143 const 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
147 enum true_type  {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
148 const 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  */
154 struct 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  */
170 static  int     true_start      P((int, struct peer *));
171 static  void    true_shutdown   P((int, struct peer *));
172 static  void    true_receive    P((struct recvbuf *));
173 static  void    true_poll       P((int, struct peer *));
174 static  void    true_send       P((struct peer *, const char *));
175 static  void    true_doevent    P((struct peer *, enum true_event));
176
177 #ifdef CLOCK_PPS720
178 static  u_long  true_sample720  P((void));
179 #endif
180
181 /*
182  * Transfer vector
183  */
184 struct  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
198 static void
199 true_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  */
244 static int
245 true_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  */
299 static void
300 true_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  */
318 static void
319 true_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  */
573 static void
574 true_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  */
597 static void
598 true_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  */
813 static void
814 true_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  */
848 static u_long
849 true_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
872 int refclock_true_bs;
873 #endif /* REFCLOCK */