]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 792] TrueTime TL-3 WWV refclock support
authorHarlan Stenn <stenn@ntp.org>
Tue, 28 Jan 2014 02:32:42 +0000 (21:32 -0500)
committerHarlan Stenn <stenn@ntp.org>
Tue, 28 Jan 2014 02:32:42 +0000 (21:32 -0500)
bk: 52e716caa5xqqueH2xELWtX99o0qcw

ChangeLog
html/drivers/driver5.html
ntpd/refclock_true.c

index 43c52748406127ed9d90405c1ae8b3847d51986e..2ee126cf0db6057bcb932c5858045cfde6ee66d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+* [Bug 792] TrueTime TL-3 WWV refclock support.
 (4.2.7p413) 2014/01/27 Released by Harlan Stenn <stenn@ntp.org>
 * Require a version string for perl scripts that use autogen.
 * html/ cleanup.
index 699dfa39f9d235a4e7adc494103ff1e6fecd18e3..fa19764fac3e8beac6f6de43f3813d8280a68d73 100644 (file)
@@ -4,23 +4,25 @@
 
        <head>
                <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
-               <title>TrueTime GPS/GOES/OMEGA Receivers</title>
+               <title>TrueTime GPS/GOES/OMEGA/WWV Receivers</title>
                <link href="scripts/style.css" type="text/css" rel="stylesheet">
        </head>
 
        <body>
-               <h3>TrueTime GPS/GOES/OMEGA Receivers</h3>
+               <h3>TrueTime GPS/GOES/OMEGA/WWV Receivers</h3>
                <hr>
                <h4>Synopsis</h4>
                Address: 127.127.5.<i>u</i><br>
-               Reference ID: <tt>GPS, OMEGA, GOES</tt><br>
+               Reference ID: <tt>GPS, OMEGA, GOES, WWV</tt><br>
                Driver ID: <tt>TRUETIME</tt><br>
                Serial Port: <tt>/dev/true<i>u</i></tt>; 9600 baud, 8-bits, no parity<br>
                Features: <tt>tty_clk</tt>
                <h4>Description</h4>
-               <p>This driver supports several models models of Kinemetrics/TrueTime timing receivers, including 468-DC MK III GOES Synchronized Clock, GPS- DC MK III and GPS/TM-TMD GPS Synchronized Clock, XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD), GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module), OM-DC OMEGA Synchronized Clock, and very likely others in the same model family that use the same timecode formats.</p>
+               <p>This driver supports several models models of Kinemetrics/TrueTime timing receivers, including 468-DC MK III GOES Synchronized Clock, GPS- DC MK III and GPS/TM-TMD GPS Synchronized Clock, XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD), GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module), OM-DC OMEGA Synchronized Clock, the TL-3 WWV receiver, and very likely others in the same model families that use the same timecode formats.</p>
                <p>Most of this code is originally from refclock_wwvb.c with thanks. It has been so mangled that wwvb is not a recognizable ancestor.</p>
-               <p>Timcode format: <tt>ADDD:HH:MM:SSQCL</tt> A - control A (this is stripped before we see it) Q - Quality indication (see below) C - Carriage return L - Line feed Quality codes indicate possible error of</p>
+               <p>Timcode format: <tt>ADDD:HH:MM:SSQCL</tt><br>
+A - control A (this is stripped before we see it) Q - Quality indication (see below) C - Carriage return L - Line feed</p><br>
+Quality codes indicate possible error of:
                <dl>
                        <dt>468-DC GOES Receiver<br>
                                GPS-TM/TMD Receiver
@@ -34,6 +36,9 @@
                                A-H less than 1 millisecond. Character indicates which station is being received as follows<br>
                                A = Norway, B = Liberia, C = Hawaii, D = North Dakota, E = La Reunion, F = Argentina, G = Australia, H = Japan<br>
                                The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+                        <dt>TL-3 WWV Receiver:
+                        <dd>? receiver is unlocked<br>
+                        <dd>space +/- 5 milliseconds<br>
                </dl>
                <h4>Notes on 468-DC and OMEGA receiver:</h4>
                <p>Send the clock a <tt>R</tt> or <tt>C</tt> and once per second a timestamp will appear. Send a <tt>R</tt> to get the satellite position once (GOES only).</p>
                <p><tt>fudge 127.127.5.0 time1 +0.008 time2 -0.004</tt></p>
                <p>This corrects the 4 milliseconds advance and 8 milliseconds retard needed. The software will ask the clock which satellite it sees.</p>
                <p>The PCL720 from PC Labs has an Intel 8253 look-alike, as well as a bunch of TTL input and output pins, all brought out to the back panel. If you wire a PPS signal (such as the TTL PPS coming out of a GOES or other Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the number of microseconds since the last PPS upward edge, mediated by reading OUT0 to find out if the counter has wrapped around (this happens if more than 65535us (65ms) elapses between the PPS event and our being called.)</p>
+                <h4>Notes on the TL-3 receiver:</h4>
+                <p>The mini-DIN RS-232 port uses the Apple pinout.<br>
+                Send the clock ST1 to turn on continuous (1/sec) timecodes.
+You can also enable "mode C" via the front panel.  ST0 turns off this mode.<br>
+QV will return the firmware revision (and is useful in identifying this clock.)<br>
+QW will return its weekly signal log, useful if you're testing antennas.  You may wish to turn the loss interval down from 4h (04) to 1h (01), so the receiver declares itself unlocked sooner.  When in holdover, drift can be on the order of 10 ms/hr since there is no high quality reference oscillator.</p>
                <h4>Monitor Data</h4>
                <p>When enabled by the <tt>flag4</tt> fudge flag, every received timecode is written as-is to the <tt>clockstats</tt> file.</p>
                <h4>Fudge Factors</h4>
@@ -61,7 +72,7 @@
                        <dt><tt>flag3 0 | 1</tt>
                        <dd>Not used by this driver.
                        <dt><tt>flag4 0 | 1</tt>
-                       <dd>Not used by this driver.
+                       <dd>Enable verbose <tt>clockstats</tt> recording if set.
                </dl>
                <h4>Additional Information</h4>
                <p><a href="../refclock.html">Reference Clock Drivers</a></p>
index dcbed76bded5ef80c16f7538b3a04de4ba91f689..04a1001f4341f23e55dd1657ab22360c2cd222fa 100644 (file)
@@ -1,9 +1,8 @@
 /*
- * refclock_true - clock driver for the Kinemetrics Truetime receivers
+ * refclock_true - clock driver for the Kinemetrics/TrueTime receivers
  *     Receiver Version 3.0C - tested plain, with CLKLDISC
- *     Developement work being done:
- *     - Properly handle varying satellite positions (more acurately)
- *     - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers
+ *     Development work being done:
+ *      - Support TL-3 WWV TOD receiver
  */
 
 #ifdef HAVE_CONFIG_H
@@ -50,10 +49,11 @@ extern int async_write(int, const void *, unsigned int);
 
 /*
  * Support for Kinemetrics Truetime Receivers
- *     GOES
- *     GPS/TM-TMD
- *     XL-DC           (a 151-602-210, reported by the driver as a GPS/TM-TMD)
- *     GPS-800 TCU     (an 805-957 with the RS232 Talker/Listener module)
+ *     GOES:           (468-DC, usable with GPS->GOES converting antenna)
+ *     GPS/TM-TMD:     
+ *     XL-DC:          (a 151-602-210, reported by the driver as a GPS/TM-TMD)
+ *     GPS-800 TCU:    (an 805-957 with the RS232 Talker/Listener module)
+ *      TL-3:           3 channel WWV/H receiver w/ IRIG and RS-232 outputs
  *     OM-DC:          getting stale ("OMEGA")
  *
  * Most of this code is originally from refclock_wwvb.c with thanks.
@@ -71,6 +71,9 @@ extern int async_write(int, const void *, unsigned int);
  *       ?     +/- 1  milliseconds     #     +/- 100 microseconds
  *       *     +/- 10 microseconds     .     +/- 1   microsecond
  *     space   less than 1 microsecond
+ *   TL-3 Receiver: (default quality codes for TL-3)
+ *       ?     unknown quality (receiver is unlocked)
+ *     space   +/- 5 milliseconds
  *   OM-DC OMEGA Receiver: (default quality codes for OMEGA)
  *   WARNING OMEGA navigation system is no longer existent
  *       >     >+- 5 seconds
@@ -103,16 +106,27 @@ extern int async_write(int, const void *, unsigned int);
  * This corrects the 4 milliseconds advance and 8 milliseconds retard
  * needed. The software will ask the clock which satellite it sees.
  *
- * Ntp.conf parameters:
- * time1 - offset applied to samples when reading WEST satellite (default = 0)
- * time2 - offset applied to samples when reading EAST satellite (default = 0)
- * val1  - stratum to assign to this clock (default = 0)
- * val2  - refid assigned to this clock (default = "TRUE", see below)
- * flag1 - will silence the clock side of ntpd, just reading the clock
- *        without trying to write to it.  (default = 0)
- * flag2 - generate a debug file /tmp/true%d.
- * flag3 - enable ppsclock streams module
- * flag4 - use the PCL-720 (BSD/OS only)
+ * Notes on the TrueTime TimeLink TL-3 WWV TOD receiver:
+ * 
+ * This clock may be polled, or send one timecode per second.
+ * That mode may be toggled via the front panel ("C" mode), or controlled
+ * from the RS-232 port.  Send the receiver "ST1" to turn it on, and
+ * "ST0" to turn it off.  Send "QV" to get the firmware revision (useful
+ * for identifying this model.)
+ * 
+ * Note that it can take several polling cycles, especially if the receiver
+ * was in the continuous timecode mode.  (It can be slow to leave that mode.)
+ * 
+ * ntp.conf parameters:
+ * time1   - offset applied to samples when reading WEST satellite (default = 0)
+ * time2   - offset applied to samples when reading EAST satellite (default = 0)
+ * stratum - stratum to assign to this clock (default = 0)
+ * refid   - refid assigned to this clock (default = "TRUE", see below)
+ * flag1   - will silence the clock side of ntpd, just reading the clock
+ *          without trying to write to it.  (default = 0)
+ * flag2   - generate a debug file /tmp/true%d.
+ * flag3   - enable ppsclock streams module
+ * flag4   - use the PCL-720 (BSD/OS only)
  */
 
 
@@ -139,19 +153,19 @@ extern int async_write(int, const void *, unsigned int);
  * used by the state machine
  */
 enum true_event        {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
-                e_Poll, e_Location, e_TS, e_Max};
+                e_TL3, e_Poll, e_Location, e_TS, e_Max};
 const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
-                       "Poll", "Location", "TS"};
+                       "TL3", "Poll", "Location", "TS"};
 #define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
 
 enum true_state        {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
-                s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
+                s_InqTL3, s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
 const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
-                       "Init", "F18", "F50", "Start", "Auto"};
+                       "InqTL3", "Init", "F18", "F50", "Start", "Auto"};
 #define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
 
-enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
-const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"};
+enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_tl3, t_Max};
+const char *types[] = {"unknown", "goes", "tm", "tcu", "omega", "tl3"};
 #define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
 
 /*
@@ -457,6 +471,19 @@ true_receive(
                return;
        }
 
+        /*
+         * Timecode: "VER xx.xx"
+         * (from a TL3 when sent "QV", so id's it during initialization.)
+         */
+        if (pp->a_lastcode[0] == 'V' && pp->a_lastcode[1] == 'E' &&
+            pp->a_lastcode[2] == 'R' && pp->a_lastcode[6] == '.') {
+                true_doevent(peer, e_TL3);
+                NLOG(NLOG_CLOCKSTATUS) {
+                        msyslog(LOG_INFO, "TL3: %s", pp->a_lastcode);
+                }
+                return;
+        }
+
        /*
         * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
         * (from a TM/TMD/XL clock during initialization.)
@@ -560,7 +587,13 @@ true_receive(
                if (!up->polled)
                        return;
 
-               true_doevent(peer, e_Poll);
+                /* We only call doevent if additional things need be done
+                 * at poll interval.  Currently, its only for GOES.  We also
+                 * call it for clock unknown so that it gets logged.
+                 */
+                if (up->type == t_goes || up->type == t_unknown)
+                    true_doevent(peer, e_Poll);
+
                if (!refclock_process(pp)) {
                        refclock_report(peer, CEVNT_BADTIME);
                        return;
@@ -685,6 +718,19 @@ true_doevent(
                        break;
                case e_F18:
                        true_send(peer, "F50\r");
+                        /*
+                         * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
+                         * (from a TM/TMD/XL clock during initialization.)
+                         */
+                        if ( strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
+                            strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
+                                true_doevent(peer, e_F18);
+                                NLOG(NLOG_CLOCKSTATUS) {
+                                    msyslog(LOG_INFO, "TM/TMD/XL: %s", 
+                                            pp->a_lastcode);
+                                }
+                                return;
+                        }
                        up->state = s_F18;
                        break;
                case e_F50:
@@ -725,7 +771,21 @@ true_doevent(
                        break;
                }
                break;
+       case t_tl3:
+                switch (event) {
+                    case e_Init:
+                        true_send(peer, "ST1"); /* Turn on continuous stream */
+                        break;
+                    case e_TS:
+                        up->state = s_Auto;
+                        break;
+                    default:
+                        break;
+                }
+                break;
        case t_unknown:
+               if (event == e_Poll)
+                   break;
                switch (up->state) {
                case s_Base:
                        if (event != e_Init)
@@ -740,13 +800,39 @@ true_doevent(
                                true_doevent(peer, e_Init);
                                break;
                        case e_Init:    /*FALLTHROUGH*/
-                       case e_Huh:     /*FALLTHROUGH*/
+                       case e_Huh:
                        case e_TS:
+                                true_send(peer, "ST0"); /* turn off TL3 auto */
+                                sleep(1);               /* wait for it */
+                                up->state = s_InqTL3;
+                                true_send(peer, "QV");  /* see if its a TL3 */
+                                break;
+                            default:
+                                abort();
+                        }
+                        break;
+                    case s_InqTL3:
+                        switch (event) {
+                            case e_TL3:
+                                up->type = t_tl3;
+                                up->state = s_Auto;     /* Inq side-effect. */
+                                true_send(peer, "ST1"); /* Turn on 1/sec data */
+                                break;
+                            case e_Init:        /*FALLTHROUGH*/
+                            case e_Huh:
                                up->state = s_InqOmega;
                                true_send(peer, "C\r");
                                break;
+                            case e_TS:
+                                 up->type = t_tl3;    /* Already sending data */
+                                 up->state = s_Auto;
+                                 break;
+                            case e_Poll:
+                                break;
                        default:
-                               abort();
+                                msyslog(LOG_INFO, 
+                                        "TRUE: TL3 init fellthrough!");
+                                break; 
                        }
                        break;
                case s_InqOmega:
@@ -776,7 +862,9 @@ true_doevent(
                                up->state = s_InqTCU;
                                break;
                        default:
-                               abort();
+                                msyslog(LOG_INFO, 
+                                        "TRUE: TM/TMD init fellthrough!");
+                               break;
                        }
                        break;
                case s_InqTCU:
@@ -791,7 +879,9 @@ true_doevent(
                                sleep(1);       /* XXX */
                                break;
                        default:
-                               abort();
+                                msyslog(LOG_INFO, 
+                                        "TRUE: TCU init fellthrough!");
+                                break;
                        }
                        break;
                        /*
@@ -809,7 +899,8 @@ true_doevent(
                }
                break;
        default:
-               abort();
+                msyslog(LOG_INFO, "TRUE: cannot identify refclock!");
+               abort();    
                /* NOTREACHED */
        }