]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Many files:
authorClaas Hilbrecht <hilbrecht@ntp.org>
Thu, 18 Jul 2002 15:44:35 +0000 (17:44 +0200)
committerClaas Hilbrecht <hilbrecht@ntp.org>
Thu, 18 Jul 2002 15:44:35 +0000 (17:44 +0200)
  support for new refclock driver NeoClock4X
neoclock4x.gif, driver44.htm, refclock_neoclock4x.c:
  support for new refclock driver NeoClock4X

bk: 3d36e263qTcPxtPlcslZINzm5H40zQ

configure.in
html/driver44.htm [new file with mode: 0755]
html/pic/neoclock4x.gif [new file with mode: 0755]
html/refclock.htm
include/ntp.h
libntp/clocktypes.c
ntpd/Makefile.am
ntpd/ntp_control.c
ntpd/refclock_conf.c
ntpd/refclock_neoclock4x.c [new file with mode: 0644]

index 8503d6cded124c45adb3b2c587bc3e0251b839ab..ae9d6de3bd6da75f0a387b8d1726130d1e67c2d1 100644 (file)
@@ -2152,6 +2152,15 @@ if test "$ntp_ok" = "yes"; then
 fi
 AC_MSG_RESULT($ntp_ok)
 
+AC_MSG_CHECKING(for NeoClock4X receiver)
+AC_ARG_ENABLE(NEOCLOCK4X,
+    AC_HELP_STRING([--enable-NEOCLOCK4X], [+ NeoClock4X DCF77 / TDF receiver]),
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_NEOCLOCK4X, 1, [NeoClock4X])
+fi
+AC_MSG_RESULT($ntp_ok)
 
 AC_MSG_CHECKING(for default inclusion of all suitable PARSE clocks)
 AC_ARG_ENABLE(parse-clocks,    [  --enable-parse-clocks   - include all suitable PARSE clocks:],
diff --git a/html/driver44.htm b/html/driver44.htm
new file mode 100755 (executable)
index 0000000..0d29384
--- /dev/null
@@ -0,0 +1,131 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+  <title>NeoClock4X</title>\r
+                    \r
+  <meta http-equiv="content-type"\r
+ content="text/html; charset=ISO-8859-15">\r
+</head>\r
+  <body>\r
+     \r
+<h1>NeoClock4X - DCF77 / TDF serial line receiver<br>\r
+  </h1>\r
+   \r
+<hr width="100%" size="2">   \r
+<h2>Synopsis</h2>\r
+   \r
+<table cellpadding="0" cellspacing="0" border="0" width="100%">\r
+    <tbody>\r
+      <tr>\r
+        <td valign="top">              \r
+      <table cellpadding="2" cellspacing="0" border="0" width="100%">\r
+     <tbody>\r
+       <tr>\r
+         <td valign="top">Adress<br>\r
+         </td>\r
+         <td valign="top">127.127.44.u<br>\r
+         </td>\r
+       </tr>\r
+       <tr>\r
+         <td valign="top">Reference ID<br>\r
+         </td>\r
+         <td valign="top">neol<br>\r
+         </td>\r
+       </tr>\r
+       <tr>\r
+         <td valign="top">Driver ID<br>\r
+         </td>\r
+         <td valign="top">NEOCLK4X<br>\r
+         </td>\r
+       </tr>\r
+       <tr>\r
+         <td valign="top">Serial Port<br>\r
+         </td>\r
+         <td valign="top">/dev/neoclock4x-u<br>\r
+         </td>\r
+       </tr>\r
+                       \r
+        </tbody>               \r
+      </table>\r
+        <br>\r
+        </td>\r
+        <td valign="top" align="right"><a href="http://www.linum.com"><img\r
+ src="pic/neoclock4x.gif" alt="NeoClock4X - DCF77 receiver" width="150"\r
+ height="195">\r
+        </a><br>\r
+        </td>\r
+      </tr>\r
+       \r
+  </tbody>  \r
+</table>\r
+     \r
+<hr width="100%" size="2">   \r
+<h2>Description</h2>\r
+   The refclock_neoclock4x driver supports the NeoClock4X receiver available\r
+ from <a href="http://www.linum.com">Linum Software GmbH</a>. The receiver \r
+ is available as a <a href="http://www.dcf77.de">DCF77</a> or TDF receiver.\r
+ Both receivers have the same output string. For more information about the\r
+ NeoClock4X receiver please visit <a\r
+ href="http://www.linum.com/redir/jump/id=neoclock4x&amp;action=redir">http://www.linum.com/redir/jump/id=neoclock4x&amp;action=redir</a>.\r
+    \r
+<hr width="100%" size="2">   \r
+<h2>Fudge Factors</h2>\r
+        \r
+<dl>\r
+  <dt>  <b><a href="clockopt.htm">time1 time</a></b></dt>\r
+  <dd> Specifies the time offset calibration factor  with the default value\r
+ off 0.16958333 seconds. This offset is used  to correct serial line and\r
+operating  system delays incurred in capturing time stamps. If you want to\r
+fudge the  time1 offset <b>ALWAYS</b> add a value off 0.16958333. This is\r
+neccessary  to compensate to delay that is caused by transmit the timestamp\r
+at 2400 Baud. If you want to compensate the delay that the DCF77 or TDF radio\r
+signal takes to travel to your site simply add the needed millisecond delay\r
+to the given value. Note that the time here is given in seconds.</dd>\r
+  <dd>Default setting is 0.16958333 seconds.<br>\r
+    </dd>\r
+</dl>\r
+     \r
+<dl>\r
+  <dt> <b><a href="file:///E:/ntp-4.1.1a/html/clockopt.htm">time2 time</a></b></dt>\r
+  <dd> Not used by this driver.</dd>\r
+</dl>\r
\r
+<dl>\r
+  <dt> <a href="clockopt.htm"><b>flag1 0 | 1</b></a></dt>\r
+  <dd>When set to 1 the driver will feed ntp with timestampe even if the\r
+radio signal is lost. In this case an internal backup clock generates the\r
+timestamps. This is ok as long as the receiver is synced once since the receiver\r
+is able to keep time for a long period.</dd>\r
+  <dd>Default setting is 0 = don't synchronize to CMOS clock.<br>\r
+    </dd>\r
+  <dd><br>\r
+    </dd>\r
+  <dt> <a href="clockopt.htm"><b>flag2 0 | 1</b></a></dt>\r
+  <dd>You can allow the NeoClock4X driver to use the quartz clock even if\r
+ it is never synchronized to a radio clock. This is usally not a good idea\r
+ if you want preceise timestamps since the CMOS clock is maybe not adjusted\r
+ to a dst status change. So <b>PLEASE</b> switch this only on if you now\r
+what  you're doing.</dd>\r
+  <dd>Default setting is 0 = don't synchronize to unsynchronized CMOS clock.<br>\r
+    </dd>\r
+  <dt><br>\r
+   </dt>\r
+  <dt><a href="clockopt.htm"><b>flag3 0 | 1</b></a></dt>\r
+  <dd> Not used by this driver.<tt><tt><tt><tt><tt><tt> </tt></tt></tt></tt></tt></tt></dd>\r
+  <dd><br>\r
+    </dd>\r
+  <dt> <a href="clockopt.htm"><b>flag4 0 | 1</b></a></dt>\r
+  <dd>It is recommended to allow extensive logging while you setup the NeoClock4X\r
+ receiver. If you activate flag4 every received data is logged. You should\r
+ turn off flag4 as soon as the clock works as expected to reduce logfile\r
+cluttering.</dd>\r
+  <dd>Default setting is 0 = don't log received data and converted utc time.<br>\r
+   </dd>\r
+</dl>\r
+   \r
+<hr width="100%" size="2">Please send any comments or question to <a\r
+ href="mailto:neoclock4@linum.com">neoclock4x@linum.com</a>.<br>\r
+  <br>\r
+ <br>\r
+</body>\r
+</html>\r
diff --git a/html/pic/neoclock4x.gif b/html/pic/neoclock4x.gif
new file mode 100755 (executable)
index 0000000..4df95af
Binary files /dev/null and b/html/pic/neoclock4x.gif differ
index 079babac20487ca30a28180b6638671e5d98311f..df4af3a9dfe365ec4f453b6b9a1058a22f10f3e5 100644 (file)
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 <html>
 <head>
-<meta name="generator" content="HTML Tidy, see www.w3.org">
-<title>Reference Clock Drivers</title>
+  <meta name="generator" content="HTML Tidy, see www.w3.org">
+  <title>Reference Clock Drivers</title>
 </head>
-<body>
+  <body>
 <h3>Reference Clock Drivers</h3>
-
-<img align="left" src="pic/stack1a.jpg" alt="gif">Master Time
-Facility at the <a href="http://www.eecis.udel.edu/~mills/lab.htm">
-UDel Internet Research Laboratory</a>: <br clear="left">
-<hr>
-<p>Support for most of the commonly available radio and modem
-reference clocks is included in the default configuration of the
-NTP daemon for Unix <tt>ntpd</tt>. Individual clocks can be
-activated by configuration file commands, specifically the <tt>
-server</tt> and <tt>fudge</tt> commands described in the <a href=
-"ntpd.htm"><tt>ntpd</tt> program manual page</a>. The following
-discussion presents Information on how to select and configure the
-device drivers in a running Unix system.</p>
-
-<p>Many radio reference clocks can be set to display local time as
-adjusted for timezone and daylight saving mode. For use with NTP
-the clock must be set for Coordinated Universal Time (UTC) only.
-Ordinarily, these adjustments are performed by the kernel, so the
-fact that the clock runs on UTC will be transparent to the
-user.</p>
-
-<p>Radio and modem clocks by convention have addresses in the form
-127.127.<i>t.u</i>, where <i>t</i> is the clock type and <i>u</i>
-is a unit number in the range 0-3 used to distinguish multiple
-instances of clocks of the same type. Most of these clocks require
-support in the form of a serial port or special bus peripheral, but
-some can work directly from the audio codec found in some
-workstations. The particular device is normally specified by adding
-a soft link <tt>/dev/device<i>u</i></tt> to the particular hardware
-device involved, where <i><tt>u</tt></i> correspond to the unit
-number above.</p>
-
-<p>Most clock drivers communicate with the reference clock using a
-serial port, usually at 9600 bps. There are several application
-program interfaces (API) used in the various Unix and NT systems,
-most of which can be detected at configuration time. Thus, it is
-important that the NTP daemon and utilities be compiled on the
-target system or clone. In some cases special features are
-available, such as timestamping in the kernel or pulse-per-second
-(PPS) interface. In most cases these features can be detected at
-configuration time as well; however, the kernel may have to be
-recompiled in order for them to work.</p>
-
-<p>The audio drivers are a special case. These include support for
-the NIST time/frequency stations WWV and WWVH, the Canadian
-time/frequency station CHU and generic IRIG signals. Currently,
-support for the Solaris and SunOS audio API is included in the
-distribution. It is left to the volunteer corps to extend this
-support to other systems. Further information on hookup, debugging
-and monitoring is given in the <a href="audio.htm">Audio
-Drivers</a> page.</p>
-
-<p>The local clock driver is also a special case. A server
-configured with this driver can operate as a primary server to
-synchronize other clients when no other external synchronization
-sources are available. If the server is connected directly or
-indirectly to the public Internet, there is some danger that it can
-adversely affect the operation of unrelated clients. Carefully read
-the <a href="driver1.htm">Undisciplined Local Clock</a> page and
-respect the stratum limit.</p>
-
-<p>The local clock driver also supports an external synchronization
-source such as a high resolution counter disciplined by a GPS
-receiver, for example. Further information is on the <a href=
-"extern.htm">External Clock Discipline and the Local Clock
-Driver</a> page.</p>
-
+  <img align="left" src="pic/stack1a.jpg" alt="gif">
+Master Time Facility at the <a
+ href="http://www.eecis.udel.edu/%7Emills/lab.htm"> UDel Internet Research
+Laboratory</a>: <br clear="left">
+<hr> 
+<p>Support for most of the commonly available radio and modem reference clocks
+is included in the default configuration of the NTP daemon for Unix <tt>ntpd</tt>.
+Individual clocks can be activated by configuration file commands, specifically
+the <tt> server</tt> and <tt>fudge</tt> commands described in the <a
+ href="ntpd.htm"><tt>ntpd</tt> program manual page</a>. The following discussion
+presents Information on how to select and configure the device drivers in
+a running Unix system.</p>
+  
+<p>Many radio reference clocks can be set to display local time as adjusted
+for timezone and daylight saving mode. For use with NTP the clock must be
+set for Coordinated Universal Time (UTC) only. Ordinarily, these adjustments
+are performed by the kernel, so the fact that the clock runs on UTC will
+be transparent to the user.</p>
+  
+<p>Radio and modem clocks by convention have addresses in the form 127.127.<i>t.u</i>,
+where <i>t</i> is the clock type and <i>u</i> is a unit number in the range
+0-3 used to distinguish multiple instances of clocks of the same type. Most
+of these clocks require support in the form of a serial port or special bus
+peripheral, but some can work directly from the audio codec found in some 
+workstations. The particular device is normally specified by adding a soft
+link <tt>/dev/device<i>u</i></tt> to the particular hardware device involved,
+where <i><tt>u</tt></i> correspond to the unit number above.</p>
+  
+<p>Most clock drivers communicate with the reference clock using a serial
+port, usually at 9600 bps. There are several application program interfaces
+(API) used in the various Unix and NT systems, most of which can be detected
+at configuration time. Thus, it is important that the NTP daemon and utilities
+be compiled on the target system or clone. In some cases special features
+are available, such as timestamping in the kernel or pulse-per-second (PPS)
+interface. In most cases these features can be detected at configuration
+time as well; however, the kernel may have to be recompiled in order for
+them to work.</p>
+  
+<p>The audio drivers are a special case. These include support for the NIST
+time/frequency stations WWV and WWVH, the Canadian time/frequency station
+CHU and generic IRIG signals. Currently, support for the Solaris and SunOS
+audio API is included in the distribution. It is left to the volunteer corps
+to extend this support to other systems. Further information on hookup, debugging 
+and monitoring is given in the <a href="audio.htm">Audio Drivers</a> page.</p>
+  
+<p>The local clock driver is also a special case. A server configured with
+this driver can operate as a primary server to synchronize other clients
+when no other external synchronization sources are available. If the server
+is connected directly or indirectly to the public Internet, there is some
+danger that it can adversely affect the operation of unrelated clients. Carefully
+read the <a href="driver1.htm">Undisciplined Local Clock</a> page and respect
+the stratum limit.</p>
+  
+<p>The local clock driver also supports an external synchronization source
+such as a high resolution counter disciplined by a GPS receiver, for example.
+Further information is on the <a href="extern.htm">External Clock Discipline
+and the Local Clock Driver</a> page.</p>
+  
 <h4>Driver Calibration</h4>
-
-<p>Some drivers depending on longwave and shortwave radio services
-need to know the radio propagation time from the transmitter to the
-receiver, which can amount to some tens of milliseconds. This must
-be calculated for each specific receiver location and requires the
-geographic coordinates of both the transmitter and receiver. The
-transmitter coordinates for various radio services are given in the
-<a href="qth.htm">Stations, Frequencies and Geographic
-Coordinates</a> page. Receiver coordinates can be obtained or
-estimated from various sources. The actual calculations are beyond
-the scope of this document.</p>
-
-<p>When more than one clock driver is supported, it is often the
-case that each shows small systematic offset differences relative
-to the rest. To reduce the effects of jitter when switching from
-one driver to the another, it is useful to calibrate the drivers to
-a common ensemble offset. The <tt>enable calibrate</tt>
-configuration command in the <a href="miscopt.htm">Miscellaneous
-Options</a> page is useful for this purpose. The calibration
-function can also be enabled and disabled using the <tt>ntpdc</tt>
-program utility.</p>
-
-<p>Most clock drivers use the <tt>time1</tt> value specified in the
-<tt>fudge</tt> configuration command to provide the calibration
-correction when this cannot be provided by the clock or interface.
-When the calibration function is enabled, the <tt>time1</tt> value
-is automatically adjusted to match the offset of the remote server
-or local clock driver selected for synchronization. Ordinarily, the
-NTP selection algorithm chooses the best from among all sources,
-usually the best radio clock determined on the basis of stratum,
-synchronization distance and jitter. The calibration function
-adjusts the <tt>time1</tt> values for all clock drivers except this
-source so that their indicated offsets tend to zero. If the
-selected source is the kernel PPS discipline, the <tt>fudge
+  
+<p>Some drivers depending on longwave and shortwave radio services need to
+know the radio propagation time from the transmitter to the receiver, which
+can amount to some tens of milliseconds. This must be calculated for each
+specific receiver location and requires the geographic coordinates of both
+the transmitter and receiver. The transmitter coordinates for various radio
+services are given in the <a href="qth.htm">Stations, Frequencies and Geographic 
+Coordinates</a> page. Receiver coordinates can be obtained or estimated from
+various sources. The actual calculations are beyond the scope of this document.</p>
+  
+<p>When more than one clock driver is supported, it is often the case that
+each shows small systematic offset differences relative to the rest. To reduce
+the effects of jitter when switching from one driver to the another, it is
+useful to calibrate the drivers to a common ensemble offset. The <tt>enable
+calibrate</tt> configuration command in the <a href="miscopt.htm">Miscellaneous 
+Options</a> page is useful for this purpose. The calibration function can
+also be enabled and disabled using the <tt>ntpdc</tt> program utility.</p>
+  
+<p>Most clock drivers use the <tt>time1</tt> value specified in the <tt>fudge</tt>
+configuration command to provide the calibration correction when this cannot
+be provided by the clock or interface. When the calibration function is enabled,
+the <tt>time1</tt> value is automatically adjusted to match the offset of
+the remote server or local clock driver selected for synchronization. Ordinarily,
+the NTP selection algorithm chooses the best from among all sources, usually
+the best radio clock determined on the basis of stratum, synchronization
+distance and jitter. The calibration function adjusts the <tt>time1</tt>
+values for all clock drivers except this source so that their indicated offsets
+tend to zero. If the selected source is the kernel PPS discipline, the <tt>fudge 
 time1</tt> values for all clock drivers are adjusted.</p>
-
-<p>The adjustment function is an exponential average designed to
-improve accuracy, so the function takes some time to converge. The
-recommended procedure is to enable the function, let it run for an
-hour or so, then edit the configuration file using the <tt>
-time1</tt> values displayed by the <tt>ntpq</tt> utility and <tt>
-clockvar</tt> command. Finally, disable the calibration function to
-avoid possible future disruptions due to misbehaving clocks or
-drivers.</p>
-
+  
+<p>The adjustment function is an exponential average designed to improve
+accuracy, so the function takes some time to converge. The recommended procedure
+is to enable the function, let it run for an hour or so, then edit the configuration
+file using the <tt> time1</tt> values displayed by the <tt>ntpq</tt> utility
+and <tt> clockvar</tt> command. Finally, disable the calibration function
+to avoid possible future disruptions due to misbehaving clocks or drivers.</p>
+  
 <h4>Performance Enhancements</h4>
-
-<p>In general, performance can be improved, especially when more
-than one clock driver is supported, to use the prefer peer function
-described in the <a href="prefer.htm">Mitigation Rules and the <tt>
-prefer</tt> Keyword</a> page. The prefer peer is ordinarily
-designated the remote peer or local clock driver which provides the
-best quality time. All other things equal, only the prefer peer
-source is used to discipline the system clock and jitter-producing
-"clockhopping" between sources is avoided. This is valuable when
-more than one clock driver is present and especially valuable when
-the PPS clock driver (type 22) is used. Support for PPS signals is
-summarized in the <a href="pps.htm">Pulse-per-second (PPS) Signal
-Interfacing</a> page.</p>
-
-<p>Where the highest performance is required, generally better than
-one millisecond, additional hardware and/or software functions may
-be required. Kernel modifications for precision time are described
-in the <a href="kern.htm">A Kernel Model for Precision
-Timekeeping</a> page. Special line discipline and streams modules
+  
+<p>In general, performance can be improved, especially when more than one
+clock driver is supported, to use the prefer peer function described in the
+<a href="prefer.htm">Mitigation Rules and the <tt> prefer</tt> Keyword</a>
+page. The prefer peer is ordinarily designated the remote peer or local clock
+driver which provides the best quality time. All other things equal, only
+the prefer peer source is used to discipline the system clock and jitter-producing 
+"clockhopping" between sources is avoided. This is valuable when more than
+one clock driver is present and especially valuable when the PPS clock driver
+(type 22) is used. Support for PPS signals is summarized in the <a
+ href="pps.htm">Pulse-per-second (PPS) Signal Interfacing</a> page.</p>
+  
+<p>Where the highest performance is required, generally better than one millisecond,
+additional hardware and/or software functions may be required. Kernel modifications
+for precision time are described in the <a href="kern.htm">A Kernel Model
+for Precision Timekeeping</a> page. Special line discipline and streams modules 
 for use in capturing precision timestamps are described in the <a
-href="ldisc.htm">Line Disciplines and Streams Drivers</a> page.</p>
-
+ href="ldisc.htm">Line Disciplines and Streams Drivers</a> page.</p>
+  
 <h4>Comprehensive List of Clock Drivers</h4>
-
-<p>Following is a list showing the type and title of each driver
-currently implemented. The compile-time identifier for each is
-shown in parentheses. Click on a selected type for specific
-description and configuration documentation, including the clock
-address, reference ID, driver ID, device name and serial line
-speed, and features (line disciplines, etc.). For those drivers
-without specific documentation, please contact the author listed in
-the <a href="copyright.htm">Copyright Notice</a> page.</p>
-
-<p><a href="driver1.htm">Type 1</a> Undisciplined Local Clock
-(<tt>LOCAL</tt>)<br>
-<a href="driver2.htm">Type 2</a> Trak 8820 GPS Receiver
-(<tt>GPS_TRAK</tt>)<br>
-<a href="driver3.htm">Type 3</a> PSTI/Traconex 1020 WWV/WWVH
-Receiver (<tt>WWV_PST</tt>)<br>
-<a href="driver4.htm">Type 4</a> Spectracom WWVB and GPS Receivers
-(<tt>WWVB_SPEC</tt>)<br>
-<a href="driver5.htm">Type 5</a> TrueTime GPS/GOES/OMEGA Receivers
-(<tt>TRUETIME</tt>)<br>
-<a href="driver6.htm">Type 6</a> IRIG Audio Decoder
-(<tt>IRIG_AUDIO</tt>)<br>
-<a href="driver7.htm">Type 7</a> Radio CHU Audio
-Demodulator/Decoder (<tt>CHU</tt>)<br>
-<a href="driver8.htm">Type 8</a> Generic Reference Driver
-(<tt>PARSE</tt>)<br>
-<a href="driver9.htm">Type 9</a> Magnavox MX4200 GPS Receiver
-(<tt>GPS_MX4200</tt>)<br>
-<a href="driver10.htm">Type 10</a> Austron 2200A/2201A GPS
-Receivers (<tt>GPS_AS2201</tt>)<br>
-<a href="driver11.htm">Type 11</a> Arbiter 1088A/B GPS Receiver
-(<tt>GPS_ARBITER</tt>)<br>
-<a href="driver12.htm">Type 12</a> KSI/Odetics TPRO/S IRIG
-Interface (<tt>IRIG_TPRO</tt>)<br>
-Type 13 Leitch CSD 5300 Master Clock Controller
-(<tt>ATOM_LEITCH</tt>)<br>
-Type 14 EES M201 MSF Receiver (<tt>MSF_EES</tt>)<br>
-<a href="driver5.htm">Type 15</a> * TrueTime generic receivers<br>
-<a href="driver16">Type 16</a> Bancomm GPS/IRIG Receiver
-(<tt>GPS_BANCOMM</tt>)<br>
-Type 17 Datum Precision Time System (<tt>GPS_DATUM</tt>)<br>
-<a href="driver18.htm">Type 18</a> NIST Modem Time Service
-(<tt>ACTS_NIST</tt>)<br>
-<a href="driver19.htm">Type 19</a> Heath WWV/WWVH Receiver
-(<tt>WWV_HEATH</tt>)<br>
-<a href="driver20.htm">Type 20</a> Generic NMEA GPS Receiver
-(<tt>NMEA</tt>)<br>
-Type 21 TrueTime GPS-VME Interface (<tt>GPS_VME</tt>)<br>
-<a href="driver22.htm">Type 22</a> PPS Clock Discipline
-(<tt>PPS</tt>)<br>
-<a href="driver23.htm">Type 23</a> PTB Modem Time Service
-(<tt>ACTS_PTB</tt>)<br>
-<a href="driver24.htm">Type 24</a> USNO Modem Time Service
-(<tt>ACTS_USNO</tt>)<br>
-<a href="driver5.htm">Type 25</a> * TrueTime generic receivers<br>
-<a href="driver26.htm">Type 26</a> Hewlett Packard 58503A GPS
-Receiver (<tt>GPS_HP</tt>)<br>
-<a href="driver27.htm">Type 27</a> Arcron MSF Receiver
-(<tt>MSF_ARCRON</tt>)<br>
-<a href="driver28.htm">Type 28</a> Shared Memory Driver
-(<tt>SHM</tt>)<br>
-<a href="driver29.htm">Type 29</a> Trimble Navigation Palisade GPS
-(<tt>GPS_PALISADE</tt>)<br>
-<a href="driver30.htm">Type 30</a> Motorola UT Oncore GPS
-(<tt>GPS_ONCORE</tt>)<br>
-Type 31 Rockwell Jupiter GPS (<tt>GPS_JUPITER</tt>)<br>
-<a href="driver32.htm">Type 32</a> Chrono-log K-series WWVB
-receiver (<tt>CHRONOLOG</tt>)<br>
-<a href="driver33.htm">Type 33</a> Dumb Clock (<tt>DUMBCLOCK</tt>)<br>
-<a href="driver34.htm">Type 34</a> Ultralink WWVB Receivers (<tt>ULINK</tt>)<br>
-<a href="driver35.htm">Type 35</a> Conrad Parallel Port Radio Clock
-(<tt>PCF</tt>)<br>
-<a href="driver36.htm">Type 36</a> Radio WWV/H Audio
-Demodulator/Decoder (<tt>WWV</tt>)<br>
-<a href="driver37.htm">Type 37</a> Forum Graphic GPS Dating station
-(<tt>FG</tt>)<br>
-<a href="driver38.htm">Type 38</a> hopf GPS/DCF77 6021/komp for
-Serial Line (<tt>HOPF_S</tt>)<br>
-<a href="driver39.htm">Type 39</a> hopf GPS/DCF77 6039 for PCI-Bus
-(<tt>HOPF_P</tt>)<br>
-<a href="driver40.htm">Type 40</a> JJY Receivers (<tt>JJY</tt>)<br>
-</p>
-
-<p>* All TrueTime receivers are now supported by one driver, type
-5. Types 15 and 25 will be retained only for a limited time and may
-be reassigned in future.</p>
-
+  
+<p>Following is a list showing the type and title of each driver currently
+implemented. The compile-time identifier for each is shown in parentheses.
+Click on a selected type for specific description and configuration documentation,
+including the clock address, reference ID, driver ID, device name and serial
+line speed, and features (line disciplines, etc.). For those drivers without
+specific documentation, please contact the author listed in the <a
+ href="copyright.htm">Copyright Notice</a> page.</p>
+  
+<p><a href="driver1.htm">Type 1</a> Undisciplined Local Clock (<tt>LOCAL</tt>)<br>
+ <a href="driver2.htm">Type 2</a> Trak 8820 GPS Receiver (<tt>GPS_TRAK</tt>)<br>
+ <a href="driver3.htm">Type 3</a> PSTI/Traconex 1020 WWV/WWVH Receiver (<tt>WWV_PST</tt>)<br>
+ <a href="driver4.htm">Type 4</a> Spectracom WWVB and GPS Receivers (<tt>WWVB_SPEC</tt>)<br>
+ <a href="driver5.htm">Type 5</a> TrueTime GPS/GOES/OMEGA Receivers (<tt>TRUETIME</tt>)<br>
+ <a href="driver6.htm">Type 6</a> IRIG Audio Decoder (<tt>IRIG_AUDIO</tt>)<br>
+ <a href="driver7.htm">Type 7</a> Radio CHU Audio Demodulator/Decoder (<tt>CHU</tt>)<br>
+ <a href="driver8.htm">Type 8</a> Generic Reference Driver (<tt>PARSE</tt>)<br>
+ <a href="driver9.htm">Type 9</a> Magnavox MX4200 GPS Receiver (<tt>GPS_MX4200</tt>)<br>
+ <a href="driver10.htm">Type 10</a> Austron 2200A/2201A GPS Receivers (<tt>GPS_AS2201</tt>)<br>
+ <a href="driver11.htm">Type 11</a> Arbiter 1088A/B GPS Receiver (<tt>GPS_ARBITER</tt>)<br>
+ <a href="driver12.htm">Type 12</a> KSI/Odetics TPRO/S IRIG Interface (<tt>IRIG_TPRO</tt>)<br>
+ Type 13 Leitch CSD 5300 Master Clock Controller (<tt>ATOM_LEITCH</tt>)<br>
+ Type 14 EES M201 MSF Receiver (<tt>MSF_EES</tt>)<br>
+ <a href="driver5.htm">Type 15</a> * TrueTime generic receivers<br>
+ <a href="driver16">Type 16</a> Bancomm GPS/IRIG Receiver (<tt>GPS_BANCOMM</tt>)<br>
+ Type 17 Datum Precision Time System (<tt>GPS_DATUM</tt>)<br>
+ <a href="driver18.htm">Type 18</a> NIST Modem Time Service (<tt>ACTS_NIST</tt>)<br>
+ <a href="driver19.htm">Type 19</a> Heath WWV/WWVH Receiver (<tt>WWV_HEATH</tt>)<br>
+ <a href="driver20.htm">Type 20</a> Generic NMEA GPS Receiver (<tt>NMEA</tt>)<br>
+ Type 21 TrueTime GPS-VME Interface (<tt>GPS_VME</tt>)<br>
+ <a href="driver22.htm">Type 22</a> PPS Clock Discipline (<tt>PPS</tt>)<br>
+ <a href="driver23.htm">Type 23</a> PTB Modem Time Service (<tt>ACTS_PTB</tt>)<br>
+ <a href="driver24.htm">Type 24</a> USNO Modem Time Service (<tt>ACTS_USNO</tt>)<br>
+ <a href="driver5.htm">Type 25</a> * TrueTime generic receivers<br>
+ <a href="driver26.htm">Type 26</a> Hewlett Packard 58503A GPS Receiver (<tt>GPS_HP</tt>)<br>
+ <a href="driver27.htm">Type 27</a> Arcron MSF Receiver (<tt>MSF_ARCRON</tt>)<br>
+ <a href="driver28.htm">Type 28</a> Shared Memory Driver (<tt>SHM</tt>)<br>
+ <a href="driver29.htm">Type 29</a> Trimble Navigation Palisade GPS (<tt>GPS_PALISADE</tt>)<br>
+ <a href="driver30.htm">Type 30</a> Motorola UT Oncore GPS (<tt>GPS_ONCORE</tt>)<br>
+ Type 31 Rockwell Jupiter GPS (<tt>GPS_JUPITER</tt>)<br>
+ <a href="driver32.htm">Type 32</a> Chrono-log K-series WWVB receiver (<tt>CHRONOLOG</tt>)<br>
+ <a href="driver33.htm">Type 33</a> Dumb Clock (<tt>DUMBCLOCK</tt>)<br>
+ <a href="driver34.htm">Type 34</a> Ultralink WWVB Receivers (<tt>ULINK</tt>)<br>
+ <a href="driver35.htm">Type 35</a> Conrad Parallel Port Radio Clock (<tt>PCF</tt>)<br>
+ <a href="driver36.htm">Type 36</a> Radio WWV/H Audio Demodulator/Decoder
+(<tt>WWV</tt>)<br>
+ <a href="driver37.htm">Type 37</a> Forum Graphic GPS Dating station (<tt>FG</tt>)<br>
+ <a href="driver38.htm">Type 38</a> hopf GPS/DCF77 6021/komp for Serial Line
+(<tt>HOPF_S</tt>)<br>
+ <a href="driver39.htm">Type 39</a> hopf GPS/DCF77 6039 for PCI-Bus (<tt>HOPF_P</tt>)<br>
+ <a href="driver40.htm">Type 40</a> JJY Receivers (<tt>JJY</tt>)<br>
+<a href="driver44.htm">Type 44</a> NeoClock4X DCF77 / TDF receiver<br>
+ </p>
+    
+<p>* All TrueTime receivers are now supported by one driver, type 5. Types
+15 and 25 will be retained only for a limited time and may be reassigned
+in future.</p>
+  
 <p>Additional Information</p>
-
-<p><a href="prefer.htm">Mitigation Rules and the <tt>prefer</tt>
-Keyword</a><br>
-<a href="rdebug.htm">Debugging Hints for Reference Clock
-Drivers</a><br>
-<a href="kern.htm">A Kernel Model for Precision Timekeeping</a><br>
-<a href="ldisc.htm">Line Disciplines and Streams Drivers</a><br>
-<a href="audio.htm">Reference Clock Audio Drivers</a><br>
-<a href="pps.htm">Pulse-per-second (PPS) Signal Interfacing</a><br>
-<a href="howto.htm">How To Write a Reference Clock Driver</a></p>
-
-<hr>
-<a href="index.htm"><img align="left" src="pic/home.gif" alt=
-"gif"></a> 
-
-<address><a href="mailto:mills@udel.edu">David L. Mills
-&lt;mills@udel.edu&gt;</a></address>
+  
+<p><a href="prefer.htm">Mitigation Rules and the <tt>prefer</tt> Keyword</a><br>
+ <a href="rdebug.htm">Debugging Hints for Reference Clock Drivers</a><br>
+ <a href="kern.htm">A Kernel Model for Precision Timekeeping</a><br>
+ <a href="ldisc.htm">Line Disciplines and Streams Drivers</a><br>
+ <a href="audio.htm">Reference Clock Audio Drivers</a><br>
+ <a href="pps.htm">Pulse-per-second (PPS) Signal Interfacing</a><br>
+ <a href="howto.htm">How To Write a Reference Clock Driver</a></p>
+  
+<hr> <a href="index.htm"><img align="left" src="pic/home.gif" alt="gif">
+</a>   
+<address><a href="mailto:mills@udel.edu">David L. Mills &lt;mills@udel.edu&gt;</a></address>
+ <br>
 </body>
 </html>
-
index 353c1f394160555fc2f680d87f36d56cbf7cb1d7..5708b7c315a4b29722e67dc1b05bcd3dafe7952f 100644 (file)
@@ -461,7 +461,8 @@ struct peer {
 #define        REFCLK_TT560            41      /* TrueTime 560 IRIG-B decoder */
 #define REFCLK_ZYFER           42      /* Zyfer GPStarplus receiver  */
 #define REFCLK_RIPENCC         43      /* RIPE NCC Trimble driver */
-#define REFCLK_MAX             43      /* Grow as needed... */
+#define REFCLK_NEOCLOCK4X       44      /* NeoClock4X DCF77 or TDF receiver */
+#define REFCLK_MAX             44      /* Grow as needed... */
 
 /*
  * We tell reference clocks from real peers by giving the reference
index 4e425c544b436d5ec248121f4a6f9f75e9ef8cf1..ec99ba8814673bbce2e9c1bda37e4cd734e06702 100644 (file)
@@ -98,6 +98,8 @@ struct clktype clktypes[] = {
          "GPS_ZYFER" },
        { REFCLK_RIPENCC,       "RIPE NCC Trimble driver (43)",
          "GPS_RIPENCC" },
+       { REFCLK_NEOCLOCK4X,    "NeoClock4X DCF77 / TDF receiver (44)",
+         "NEOCLK4X"},
        { -1,                   "", "" }
 };
 
index b057cae89397c42586f09571777143232da4363c..94dfd092a6f27217f9a5509ddf35a2750ff3d910 100644 (file)
@@ -37,7 +37,7 @@ ntpd_SOURCES = cmd_args.c jupiter.h map_vme.c ntp_config.c ntp_control.c \
        refclock_pcf.c refclock_pst.c refclock_ptbacts.c refclock_shm.c \
        refclock_tpro.c refclock_trak.c refclock_true.c refclock_tt560.c \
        refclock_ulink.c refclock_usno.c refclock_wwv.c refclock_wwvb.c \
-       refclock_zyfer.c refclock_ripencc.c
+       refclock_zyfer.c refclock_ripencc.c refclock_neoclock4x.c
 
 $(PROGRAMS): $(LDADD)
 
index f1e943c30d8b71c88c1acaaf6683a78da16e2d81..d7109cabef653d9c1aa2d9ddb1bd492a7047e521 100644 (file)
@@ -399,6 +399,7 @@ static u_char clocktypes[] = {
        CTL_SST_TS_UHF,         /* REFCLK_TT560 (41) */
        CTL_SST_TS_UHF,         /* REFCLK_ZYFER (42) */
        CTL_SST_TS_UHF,         /* REFCLK_RIPENCC (43) */
+       CTL_SST_TS_UHF,         /* REFCLK_NEOCLOCK4X (44) */
 };
 
 
index 62949b0a4868a57c25ddee719f6e9bafe84109c8..04166d9f67bf7b628081f94c6eb1a0ac09a7f376 100644 (file)
@@ -264,6 +264,12 @@ extern struct refclock refclock_ripencc;
 #define refclock_ripencc refclock_none
 #endif
 
+#ifdef CLOCK_NEOCLOCK4X
+extern struct refclock refclock_neoclock4x;
+#else
+#define        refclock_neoclock4x     refclock_none
+#endif
+
 /*
  * Order is clock_start(), clock_shutdown(), clock_poll(),
  * clock_control(), clock_init(), clock_buginfo, clock_flags;
@@ -314,7 +320,8 @@ struct refclock *refclock_conf[] = {
        &refclock_jjy,          /* 40 REFCLK_JJY */
        &refclock_tt560,        /* 41 REFCLK_TT560 */
        &refclock_zyfer,        /* 42 REFCLK_ZYFER */
-       &refclock_ripencc       /* 43 REFCLK_RIPENCC */
+       &refclock_ripencc,      /* 43 REFCLK_RIPENCC */
+       &refclock_neoclock4x    /* 44 REFCLK_NEOCLOCK4X */
 };
 
 u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/ntpd/refclock_neoclock4x.c b/ntpd/refclock_neoclock4x.c
new file mode 100644 (file)
index 0000000..3b64017
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ *
+ * refclock_neoclock4x.c
+ * - NeoClock4X driver for DCF77 or FIA Timecode
+ *
+ * Date: 2002-04-27 1.0
+ *
+ * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir
+ * for details about the NeoClock4X device
+ *
+ * Copyright (C) 2002 by Linum Software GmbH <support@linum.com>
+ *                                    
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined(REFCLOCK) && (defined(CLOCK_NEOCLOCK4X))
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_control.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+
+#if defined HAVE_SYS_MODEM_H
+# include <sys/modem.h>
+# define TIOCMSET MCSETA
+# define TIOCMGET MCGETA
+# define TIOCM_RTS MRTS
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# ifdef TERMIOS_NEEDS__SVID3
+#  define _SVID3
+# endif
+# include <termios.h>
+# ifdef TERMIOS_NEEDS__SVID3
+#  undef _SVID3
+# endif
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#define NEOCLOCK4X_TIMECODELEN 37
+
+#define NEOCLOCK4X_OFFSET_SERIAL            3
+#define NEOCLOCK4X_OFFSET_RADIOSIGNAL       9
+#define NEOCLOCK4X_OFFSET_DAY              12
+#define NEOCLOCK4X_OFFSET_MONTH            14
+#define NEOCLOCK4X_OFFSET_YEAR             16
+#define NEOCLOCK4X_OFFSET_HOUR             18
+#define NEOCLOCK4X_OFFSET_MINUTE           20
+#define NEOCLOCK4X_OFFSET_SECOND           22
+#define NEOCLOCK4X_OFFSET_HSEC             24
+#define NEOCLOCK4X_OFFSET_DOW              26
+#define NEOCLOCK4X_OFFSET_TIMESOURCE       28
+#define NEOCLOCK4X_OFFSET_DSTSTATUS        29
+#define NEOCLOCK4X_OFFSET_QUARZSTATUS      30
+#define NEOCLOCK4X_OFFSET_ANTENNA1         31
+#define NEOCLOCK4X_OFFSET_ANTENNA2         33
+#define NEOCLOCK4X_OFFSET_CRC              35
+
+struct neoclock4x_unit {
+  l_fp laststamp;      /* last receive timestamp */
+  short        unit;           /* NTP refclock unit number */
+  u_long       polled;         /* flag to detect noreplies */
+  char leap_status;    /* leap second flag */
+  int  recvnow;
+  
+  char  firmware[80];
+  char  serial[7];
+  char  radiosignal[4];
+  char  timesource;
+  char  dststatus;
+  char  quarzstatus;
+  int   antenna1;
+  int   antenna2;
+  int   utc_year;
+  int   utc_month;
+  int   utc_day;
+  int   utc_hour;
+  int   utc_minute;
+  int   utc_second;
+  int   utc_msec;
+};
+
+static int     neoclock4x_start        P((int, struct peer *));
+static void    neoclock4x_shutdown     P((int, struct peer *));
+static void    neoclock4x_receive      P((struct recvbuf *));
+static void    neoclock4x_poll         P((int, struct peer *));
+static void    neoclock4x_control      P((int, struct refclockstat *, struct refclockstat *, struct peer *));
+
+static int      neol_atoi_len           P((const char str[], int *, int));
+static int      neol_hexatoi_len        P((const char str[], int *, int));
+static void     neol_jdn_to_ymd         P((unsigned long, int *, int *, int *));
+static void     neol_localtime          P((unsigned long, int* , int*, int*, int*, int*, int*));
+static unsigned long neol_mktime        P((int, int, int, int, int, int));
+static void     neol_mdelay             P((int));
+static int      neol_query_firmware     P((int, int, char *, int));
+
+struct refclock refclock_neoclock4x = {
+  neoclock4x_start,    /* start up driver */
+  neoclock4x_shutdown, /* shut down driver */
+  neoclock4x_poll,     /* transmit poll message */
+  neoclock4x_control,
+  noentry,             /* initialize driver (not used) */
+  noentry,             /* not used */
+  NOFLAGS                      /* not used */
+};
+
+static int
+neoclock4x_start(int unit,
+                struct peer *peer)
+{
+  struct neoclock4x_unit *up;
+  struct refclockproc *pp;
+  int fd;
+  char dev[20];
+  int sl232;
+  struct termios termsettings;
+  int tries;
+
+  (void) sprintf(dev, "/dev/neoclock4x-%d", unit);
+  
+  /* LDISC_STD, LDISC_RAW
+   * Open serial port. Use CLK line discipline, if available.
+   */
+  fd = refclock_open(dev, B2400, LDISC_CLK);
+  if(fd <= 0)
+    {
+      return (0);
+    }
+  
+#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
+  /* turn on RTS, and DTR for power supply */
+  /* NeoClock4x is powered from serial line */
+  if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);
+    }
+#ifdef TIOCM_RTS
+  sl232 = sl232 | TIOCM_DTR | TIOCM_RTS;       /* turn on RTS, and DTR for power supply */
+#else
+  sl232 = sl232 | CIOCM_DTR | CIOCM_RTS;       /* turn on RTS, and DTR for power supply */
+#endif
+  if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);
+    }
+  
+  if(ioctl(fd, TCGETS, (caddr_t)&termsettings) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query serial port settings: %m", unit);
+    }
+  
+  /* 2400 Baud mit 8N2 */
+  termsettings.c_cflag &= ~PARENB;
+  termsettings.c_cflag |= CSTOPB;
+  termsettings.c_cflag &= ~CSIZE;
+  termsettings.c_cflag |= CS8;
+  
+  if(ioctl(fd, TCSETS, &termsettings) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set serial port to 2400 8N2: %m", unit);
+    }
+#else
+  msyslog(LOG_EMERG, "NeoClock4X(%d): OS interface is incapable of setting DTR/RTS to power NeoClock4X",
+         unit);
+#endif
+  
+  up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit));
+  if(!(up))
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit);
+      (void) close(fd);
+      return (0);
+    }
+
+  memset((char *)up, 0, sizeof(struct neoclock4x_unit));
+  pp = peer->procptr;
+  pp->clockdesc = "NeoClock4X";
+  pp->unitptr = (caddr_t)up;
+  pp->io.clock_recv = neoclock4x_receive;
+  pp->io.srcclock = (caddr_t)peer;
+  pp->io.datalen = 0;
+  pp->io.fd = fd;
+  /* no time is given by user! use 169.583333 ms to compensate the serial line delay
+   * formula is:
+   * 2400 Baud / 11 bit = 218.18 charaters per second
+   *  (NeoClock4X timecode len)
+   */
+  pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0;
+
+  if (!io_addclock(&pp->io))
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m",unit);
+      (void) close(fd);
+      free(up);
+      return (0);
+    }
+  
+  /*
+   * Initialize miscellaneous variables
+   */
+  peer->precision = -10;
+  peer->burst = NSTAGE;
+  memcpy((char *)&pp->refid, "neol", 4);
+  
+  up->leap_status = 0;
+  up->unit = unit;
+  strcpy(up->firmware, "?");
+  strcpy(up->serial, "?");
+  strcpy(up->radiosignal, "?");
+  up->timesource  = '?';
+  up->dststatus   = '?';
+  up->quarzstatus = '?';
+  up->antenna1    = -1;
+  up->antenna2    = -1;
+  up->utc_year    = 0;
+  up->utc_month   = 0;
+  up->utc_day     = 0;
+  up->utc_hour    = 0;
+  up->utc_minute  = 0;
+  up->utc_second  = 0;
+  up->utc_msec    = 0;
+
+  for(tries=0; tries < 5; tries++)
+    {
+      /*
+       * Wait 3 second for receiver to power up
+       */
+      NLOG(NLOG_CLOCKINFO)
+       msyslog(LOG_INFO, "NeoClock4X(%d): try query NeoClock4X firmware version (%d/5)", unit, tries);
+      sleep(3);
+      if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware)))
+       {
+         break;
+       }
+    }
+
+  NLOG(NLOG_CLOCKINFO)
+    msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit);
+  
+  return (1);
+}
+
+static void
+neoclock4x_shutdown(int unit,
+                  struct peer *peer)
+{
+  struct neoclock4x_unit *up;
+  struct refclockproc *pp;
+  int sl232;
+
+  pp = peer->procptr;
+  up = (struct neoclock4x_unit *)pp->unitptr;
+
+#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
+  /* turn on RTS, and DTR for power supply */
+  /* NeoClock4x is powered from serial line */
+  if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);
+    }
+#ifdef TIOCM_RTS
+  sl232 &= ~(TIOCM_DTR | TIOCM_RTS);   /* turn on RTS, and DTR for power supply */
+#else
+  sl232 &= ~(CIOCM_DTR | CIOCM_RTS);   /* turn on RTS, and DTR for power supply */
+#endif
+  if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
+    {
+      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);
+    }
+#endif
+  msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit);
+
+  io_closeclock(&pp->io);
+  free(up);
+  NLOG(NLOG_CLOCKINFO)
+    msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit);
+}
+
+static void
+neoclock4x_receive(struct recvbuf *rbufp)
+{
+  struct neoclock4x_unit *up;
+  struct refclockproc *pp;
+  struct peer *peer;
+  unsigned long calc_utc;
+  int day;
+  int month;   /* ddd conversion */
+  int c;
+  unsigned char calc_chksum;
+  int recv_chksum;
+  
+  peer = (struct peer *)rbufp->recv_srcclock;
+  pp = peer->procptr;
+  up = (struct neoclock4x_unit *)pp->unitptr;
+  
+  /* wait till poll interval is reached */
+  if(0 == up->recvnow)
+    return;
+  
+  /* reset poll interval flag */
+  up->recvnow = 0;
+
+  /* read last received timecode */
+  pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
+  
+  if(NEOCLOCK4X_TIMECODELEN != pp->lencode)
+    {
+      NLOG(NLOG_CLOCKEVENT)
+       msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s",
+               up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode);
+      refclock_report(peer, CEVNT_BADREPLY);
+      return;
+    }
+
+  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2);
+
+  /* calculate checksum */
+  calc_chksum = 0;
+  for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++)
+    {
+      calc_chksum += pp->a_lastcode[c];
+    }
+  if(recv_chksum != calc_chksum)
+    {
+      NLOG(NLOG_CLOCKEVENT)
+       msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s",
+               up->unit, pp->a_lastcode);
+      refclock_report(peer, CEVNT_BADREPLY);
+      return;
+    }
+
+  /* Allow synchronization even is quartz clock is
+   * never initialized.
+   * WARNING: This is dangerous!
+   */  
+  up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS];
+  if(0==(pp->sloppyclockflag & CLK_FLAG2))
+    {
+      if('I' != up->quarzstatus)
+       {
+         NLOG(NLOG_CLOCKEVENT)
+           msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s",
+                   up->unit, pp->a_lastcode);
+         pp->leap = LEAP_NOTINSYNC;
+         refclock_report(peer, CEVNT_BADDATE);
+         return;
+       }
+    }
+  if('I' != up->quarzstatus)
+    {
+      NLOG(NLOG_CLOCKEVENT)
+       msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s",
+               up->unit, pp->a_lastcode);
+    }
+  
+  /*
+   * If NeoClock4X is not synchronized to a radio clock 
+   * check if we're allowed to synchronize with the quartz
+   * clock.
+   */
+  up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE];
+  if(0==(pp->sloppyclockflag & CLK_FLAG2))
+    {
+      if('A' != up->timesource)
+       {
+         /* not allowed to sync with quartz clock */
+         if(0==(pp->sloppyclockflag & CLK_FLAG1))
+           {
+             refclock_report(peer, CEVNT_BADTIME);
+             pp->leap = LEAP_NOTINSYNC;
+             return;
+           }
+       }
+    }
+
+  /* this should only used when first install is done */
+  if(pp->sloppyclockflag & CLK_FLAG4)
+    {
+      msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s",
+             up->unit, pp->a_lastcode);
+    }
+
+  /* 123456789012345678901234567890123456789012345 */
+  /* S/N123456DCF1004021010001202ASX1213CR\r\n */
+
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2);
+  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &pp->msec, 2);
+  pp->msec *= 10; /* convert 1/100s from neoclock to real miliseconds */
+  
+  memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3);
+  up->radiosignal[3] = 0;
+  memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6);
+  up->serial[6] = 0;
+  up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS];
+  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2);
+  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2);
+
+  /*
+    Validate received values at least enough to prevent internal
+    array-bounds problems, etc.
+  */
+  if((pp->hour < 0) || (pp->hour > 23) ||
+     (pp->minute < 0) || (pp->minute > 59) ||
+     (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
+     (day < 1) || (day > 31) ||
+     (month < 1) || (month > 12) ||
+     (pp->year < 0) || (pp->year > 99)) {
+    /* Data out of range. */
+    NLOG(NLOG_CLOCKEVENT)
+      msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s",
+             up->unit, pp->a_lastcode);
+    refclock_report(peer, CEVNT_BADDATE);
+    return;
+  }
+  
+  /* Year-2000 check! */
+  /* wrap 2-digit date into 4-digit */
+  
+  if(pp->year < YEAR_PIVOT) /* < 98 */
+    {
+      pp->year += 100;
+    }
+  pp->year += 1900;
+  
+  calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second);
+  calc_utc -= 3600;
+  if('S' == up->dststatus)
+    calc_utc -= 3600;
+  neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second);
+
+  /*
+    some preparations
+  */
+  pp->day = ymd2yd(pp->year,month,day);
+  pp->leap = 0;
+  
+
+  if(pp->sloppyclockflag & CLK_FLAG4)
+    {
+      msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03d",
+             up->unit,
+             pp->year, month, day,
+             pp->hour, pp->minute, pp->second, pp->msec);
+    }
+
+  up->utc_year   = pp->year;
+  up->utc_month  = month;
+  up->utc_day    = day;
+  up->utc_hour   = pp->hour;
+  up->utc_minute = pp->minute;
+  up->utc_second = pp->second;
+  up->utc_msec   = pp->msec;
+  
+  if(!refclock_process(pp))
+    {
+      NLOG(NLOG_CLOCKEVENT)
+       msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit);
+      refclock_report(peer, CEVNT_FAULT);
+      return;
+    }
+  refclock_receive(peer);
+  
+  record_clock_stats(&peer->srcadr, pp->a_lastcode);
+}
+
+static void
+neoclock4x_poll(int unit,
+               struct peer *peer)
+{
+  struct neoclock4x_unit *up;
+  struct refclockproc *pp;
+
+  pp = peer->procptr;
+  up = (struct neoclock4x_unit *)pp->unitptr;
+
+  pp->polls++;
+  up->recvnow = 1;
+}
+
+static void
+neoclock4x_control(int unit,
+                  struct refclockstat *in,
+                  struct refclockstat *out,
+                  struct peer *peer)
+{
+  struct neoclock4x_unit *up;
+  struct refclockproc *pp;
+  
+  if(NULL == peer)
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+      return;
+    }
+
+  pp = peer->procptr;
+  if(NULL == pp)
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+      return;
+    }
+
+  up = (struct neoclock4x_unit *)pp->unitptr;
+  if(NULL == up)
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
+      return;
+    }
+
+  if(NULL != in)
+    {
+      /* check to see if a user supplied time offset is given */
+      if(in->haveflags & CLK_HAVETIME1)
+       {
+         pp->fudgetime1 = in->fudgetime1;
+         NLOG(NLOG_CLOCKINFO)
+           msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.",
+                   unit, pp->fudgetime1);
+       }
+      
+      /* notify */
+      if(pp->sloppyclockflag & CLK_FLAG1)
+       {
+         NLOG(NLOG_CLOCKINFO)
+           msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit);
+       }
+      else
+       {
+         NLOG(NLOG_CLOCKINFO)
+           msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit);
+       }
+    }
+
+  if(NULL != out)
+    {
+      static char outstatus[800];      /* status output buffer */
+      char *tt;
+      char tmpbuf[80];
+      
+      outstatus[0] = '\0';
+      out->kv_list = (struct ctl_var *)0;
+      out->type    = REFCLK_NEOCLOCK4X;
+      
+      sprintf(tmpbuf, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
+             up->utc_year, up->utc_month, up->utc_day,
+             up->utc_hour, up->utc_minute, up->utc_second,
+             up->utc_msec);
+      
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "calc_utc=\"%s\"", tmpbuf);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "radiosignal=\"%s\"", up->radiosignal);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "antenna1=\"%d\"", up->antenna1);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "antenna2=\"%d\"", up->antenna2);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      if('A' == up->timesource)
+       tt += sprintf(tt, "timesource=\"radio\"");
+      else if('C' == up->timesource)
+       tt += sprintf(tt, "timesource=\"quartz\"");
+      else
+       tt += sprintf(tt, "timesource=\"unknown\"");
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      if('I' == up->quarzstatus)
+       tt += sprintf(tt, "quartzstatus=\"synchronized\"");
+      else if('X' == up->quarzstatus)
+        tt += sprintf(tt, "quartzstatus=\"not synchronized\"");
+      else
+       tt += sprintf(tt, "quartzstatus=\"unknown\"");
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      if('S' == up->dststatus)
+        tt += sprintf(tt, "dststatus=\"summer\"");
+      else if('W' == up->dststatus)
+        tt += sprintf(tt, "dststatus=\"winter\"");
+      else
+        tt += sprintf(tt, "dststatus=\"unknown\"");
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "firmware=\"%s\"", up->firmware);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+      tt += sprintf(tt, "serialnumber=\"%s\"", up->serial);
+      tt = add_var(&out->kv_list, 512, RO|DEF);
+    }
+}
+
+static int neol_hexatoi_len(const char str[],
+                           int *result,
+                           int maxlen)
+{
+  int hexdigit;
+  int i;
+  int n = 0;
+  
+  for(i=0; isxdigit(str[i]) && i < maxlen; i++)
+    {
+      hexdigit = isdigit(str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10;
+      n = 16 * n + hexdigit;
+    }
+  *result = n;
+  return (n);
+}
+
+int neol_atoi_len(const char str[],
+                 int *result,
+                 int maxlen)
+{
+  int digit;
+  int i;
+  int n = 0;
+  
+  for(i=0; isdigit(str[i]) && i < maxlen; i++)
+    {
+      digit = str[i] - '0';
+      n = 10 * n + digit;
+    }
+  *result = n;
+  return (n);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static unsigned long neol_mktime(int year,
+                                int mon,
+                                int day, 
+                                int hour,
+                                int min,
+                                int sec)
+{
+  if (0 >= (int) (mon -= 2)) {    /* 1..12 . 11,12,1..10 */
+    mon += 12;      /* Puts Feb last since it has leap day */
+    year -= 1;
+  }
+  return (((
+            (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+            year*365 - 719499
+            )*24 + hour /* now have hours */
+           )*60 + min /* now have minutes */
+          )*60 + sec; /* finally seconds */
+}
+
+static void neol_localtime(unsigned long utc,
+                          int* year,
+                          int* month,
+                          int* day,
+                          int* hour,
+                          int* minute,
+                          int* second)
+{
+  ldiv_t d;
+  
+  /* Sekunden */
+  d  = ldiv(utc, 60);
+  *second = d.rem;
+  
+  /* Minute */
+  d  = ldiv(d.quot, 60);
+  *minute = d.rem;
+  
+  /* Stunden */
+  d  = ldiv(d.quot, 24);
+  *hour = d.rem;
+  
+  /*             JDN Date 1/1/1970 */
+  neol_jdn_to_ymd(d.quot + 2440588L, year, month, day);
+}
+
+static void neol_jdn_to_ymd(unsigned long jdn, 
+                           int *yy,
+                           int *mm, 
+                           int *dd)
+{
+  unsigned long x, z, m, d, y;
+  unsigned long daysPer400Years = 146097UL;
+  unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL;
+  
+  x = jdn + 68569UL;
+  z = 4UL * x / daysPer400Years;
+  x = x - (daysPer400Years * z + 3UL) / 4UL;
+  y = 4000UL * (x + 1) / fudgedDaysPer4000Years;
+  x = x - 1461UL * y / 4UL + 31UL;
+  m = 80UL * x / 2447UL;
+  d = x - 2447UL * m / 80UL;
+  x = m / 11UL;
+  m = m + 2UL - 12UL * x;
+  y = 100UL * (z - 49UL) + y + x;
+  
+  *yy = (int)y;
+  *mm = (int)m;
+  *dd = (int)d;
+}
+
+/* 
+ *  delay in milliseconds 
+ */ 
+static void 
+neol_mdelay(int milliseconds) 
+{ 
+  struct timeval        tv; 
+  
+  if (milliseconds)
+    { 
+      tv.tv_sec  = 0; 
+      tv.tv_usec = milliseconds * 1000; 
+      select(1, NULL, NULL, NULL, &tv); 
+    } 
+}
+
+static int
+neol_query_firmware(int fd,
+                   int unit,
+                   char *firmware,
+                   int maxlen)
+{
+  unsigned char tmpbuf[256];
+  int len;
+  int lastsearch;
+  unsigned char c;
+  int last_c_was_crlf;
+  int last_crlf_conv_len;
+  int init;
+  int read_tries;
+  int flag = 0;
+
+  /* wait a little bit */
+  neol_mdelay(250);
+  if(-1 != write(fd, "V", 1))
+    {
+      /* wait a little bit */
+      neol_mdelay(250);
+      memset(tmpbuf, 0x00, sizeof(tmpbuf));
+      
+      len = 0;
+      lastsearch = 0;
+      last_c_was_crlf = 0;
+      last_crlf_conv_len = 0;
+      init = 1;
+      read_tries = 0;
+      for(;;)
+       {
+         if(read_tries++ > 500)
+           {
+             msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit);
+             strcpy(tmpbuf, "unknown due to timeout");
+             break;
+           }
+         if(-1 == read(fd, &c, 1))
+           {
+             neol_mdelay(25);
+             continue;
+           }
+         if(init)
+           {
+             if(0xA9 != c) /* wait for (c) char in input stream */
+               continue;
+             
+             strcpy(tmpbuf, "(c)");
+             len = 3;
+             init = 0;
+             continue;
+           }
+         
+         //msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c);
+         if(0x0A == c || 0x0D == c)
+           {
+             if(last_c_was_crlf)
+               {
+                 char *ptr;
+                 ptr = strstr(&tmpbuf[lastsearch], "S/N");
+                 if(NULL != ptr)
+                   {
+                     tmpbuf[last_crlf_conv_len] = 0;
+                     flag = 1;
+                     break;
+                   }
+                 /* convert \n to / */
+                 last_crlf_conv_len = len;
+                 tmpbuf[len++] = ' ';
+                 tmpbuf[len++] = '/';
+                 tmpbuf[len++] = ' ';
+                 lastsearch = len;
+               }
+             last_c_was_crlf = 1;
+           }
+         else
+           {
+             last_c_was_crlf = 0;
+             if(0x00 != c)
+               tmpbuf[len++] = c;
+           }
+         tmpbuf[len] = '\0';
+         if(len > sizeof(tmpbuf)-5)
+           break;
+       }
+    }
+  else
+    {
+      msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit);
+      strcpy(tmpbuf, "unknown error");
+    }
+  strncpy(firmware, tmpbuf, maxlen);
+  firmware[maxlen] = '\0';
+
+  if(flag)
+    {
+      NLOG(NLOG_CLOCKINFO)
+       msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware);
+    }
+
+  return (flag);
+}
+  
+#else
+int refclock_neoclock4x_bs;
+#endif /* REFCLOCK */
+
+/*
+ * History:
+ * refclock_neoclock4x.c
+ *
+ * 2002/04/27 cjh
+ * Revision 1.0  first release
+ *
+ * 2002/0715 cjh
+ * preparing for bitkeeper reposity
+ *
+ */