|Linux System Administration|
Synchronizing ntpd to a Garmin GPS 18 LVC via gpsd
Accurate time synchronization is part of the foundation of any computer network. Users expect computers to keep accurate time regardless, it makes life easier for technicians when troubleshooting network problems, and it is crucial for time-dependent applications, such as Kerberos, or most anything that includes database replication.
Every computer motherboard includes an internal clock that continues to run on a battery even when the computer is switched off. For any operating system that is installed, this clock is the default time source. Unfortunately, motherboard clocks are anything but accurate and may drift by as much as several minutes a day. In some cases the only option may be to regularly reset the clock manually, but that is a crude and labor-intensive solution prone to human error. A far more efficient solution is to permanently synchronize every computer on a network to one or more accurate and reliable time sources.
One way to achieve this is to synchronize to a few of the many Network Time Protocol (NTP) servers available on the Internet. This is a popular solution that is definitely better than having no automatic time correction at all, but it also has certain drawbacks. First of all, most Internet links are also heavily used for other purposes; this inflicts varying delay times on NTP traffic, leading to decreased accuracy. Second, NTP was designed for use with symmetric network links, so those with typically asymmetric broadband connections (e.g. ADSL) can never achieve optimal results. However, the worst problem occurs when the Internet link becomes unavailable for any significant length of time. Typically, an NTP server will then revert to using its local clock and begin to drift as a result. If it drifts too far before the network link is reestablished, it may not resynchronize automatically, thus requiring manual intervention. This is the case with the most popular NTP server available for Linux, the NTP daemon (ntpd), the argument being that such a large time difference can just as easily be due to a problem with the remote system. At least one alternative NTP daemon, Chrony, does not exhibit this behavior.
A far more reliable solution is to maintain one or more accurate time sources locally. The traditional options for this approach have always included radio receivers for time signals, which are cheap, but not too accurate, and atomic clocks, which are extremely accurate, but complex and expensive. Nowadays, there is also a third option: a GPS receiver with pulse-per-second (PPS) output. These receivers are often very affordable and relatively simple, yet capable of providing (near) microsecond accuracy, making them by far the best value for money available. All a GPS receiver needs is a relatively good view of the sky: the less obstructed the better.
The Garmin GPS 18 LVC is one such receiver. This is a puck-like device in which both the antenna and electronics are integrated. It is 19.5 mm high by 61 mm in diameter and weighs just 110.6-160.6 grams depending on the length of the cable: 3 or 5 meters, depending on the model. It includes a microprocessor, which is to an extent programmable, and an internal clock that is disciplined by the GPS receiver. If it stops receiving signals from any GPS satellites, the internal clock will continue to provide a signal, although in that case it will not be anywhere near as accurate. Production of this particular model has been discontinued, but it is still widely available, e.g. via eBay, for less than $80.00. Within the Garmin GPS 18 family, only the LVC and the 5 Hz model (also discontinued) produce a PPS signal. The Garmin 18-5Hz produces 5 pulses per second for increased accuracy, but sells for 2-3 times as much. New versions of these models are now being produced as the Garmin GPS 18x.
This page attempts to describe how to configure a Debian 5.0 (lenny) system with the GPS daemon (gpsd 2.37) and the NTP daemon (ntpd 4.2.4) and turn it into a stratum 1 NTP server using a Garmin GPS 18 LVC. It assumes that a minimal Debian operating system is already up and running and that the computer has one available 9-pin serial port (/dev/ttyS0).
The first obstacle to overcome is how to attach the Garmin GPS 18 LVC to the serial port of the computer. The cable from the GPS device consists of six or seven wires, plus a screen, that may or may not be terminated by a small plastic connector. The idea is to attach it to an RS-232 DE-9 connector, so cut off the mini-connector if it is included. The wires from the GPS device are as follows:
The Garmin GPS 18 also requires a 5V power source. This is not available from the serial port, but a simple solution is to sacrifice a USB cable for this purpose. All that is necessary is a short length of USB cable with an A-connector on one end and some exposed wires on the other: the screen, red (+5V) and black (ground) wires are the only ones required. These should be soldered, together with the GPS cable, onto a female RS-232 DE-9 connector as follows:
Garmin USB RS-232 DE-9 pin no. +5V Red ---------------+ | +5V Red -----+ GND Black ---------+ | GND Black ---------+-----+--------- 5 GND | | GND Black ---------+ | | GND Black -----+ RXD Green ------------------------- 3 TXD TXD White ------------------------- 2 RXD PPS Yellow ------------------------ 1 DCD Scr Screen --------------+--------- Screen | Screen ----+
Prepare the serial port, to which the GPS receiver is to be attached, for low-latency operation. To achieve this, install this package:
~# apt-get install setserial
It has no dependencies, so all that gets installed is:
setserial 2.17-44.2 controls configuration of serial ports
Next, edit the associated configuration file, /var/lib/setserial/autoserial.conf, and modify it so that it reads:
/dev/ttyS0 uart 16550A port 0x03f8 irq 4 baud_base 115200 spd_normal skip_test low_latency
NB: Different machines have different UART models. Faster and more modern UARTS tend to have larger internal buffers (the 16550A has a 16-byte buffer), but for this particular task it is actually better if the UART does not use a buffer at all, since it can only add more delay.
To minimize CPU utilization, serial port traffic is usually delayed by 5 to 10 ms by default. In this case, however, the low_latency setting is used, because the slightly higher CPU load is well worth the tradeoff.
To activate this change, run the startup script once more:
~# /etc/init.d/setserial Loading the saved-state of the serial devices... /dev/ttyS0 at 0x03f8 (irq = 4) is a 16550A (low_latency) ~# _
One more issue: the installer does not add anything to the /etc/rc2.d directory, so add a symlink there that points to /etc/init.d/setserial. This will ensure that, during the boot process, setserial will be run before gpsd starts:
~# ln -s /etc/init.d/setserial /etc/rc2.d/S19setserial ~# _
3. GPS daemon
The next step is to install the GPS daemon. This software will sit between the GPS device and the NTP daemon, making both the PPS signal and the NMEA 0183 data available to ntpd through a pair of shared memory (SHM) devices. It can also be used to create an interesting skyview webpage showing current GPS satellite positions.
Install these four packages:
~# apt-get install gpsd gpsd-clients libgps17 python-gps
As a result, 22 new packages will be installed, including 18 dependencies:
dbus 1.2.1-5+lenny1 simple interprocess messaging system dbus-x11 1.2.1-5+lenny1 simple interprocess messaging system (X11 deps) gpsd 2.37-7 GPS (Global Positioning System) daemon gpsd-clients 2.37-7 Clients for the GPS daemon lesstif2 1:0.95.0-2.1 OSF/Motif 2.1 implementation released under LGPL libdbus-1-3 1.2.1-5+lenny1 simple interprocess messaging system libdbus-glib-1-2 0.76-1 simple interprocess messaging system (GLib-based shared li libexpat1 2.0.1-4+lenny3 XML parsing C library - runtime library libglib2.0-0 2.16.6-3 The GLib library of C routines libglib2.0-data 2.16.6-3 Common files for GLib library libgps17 2.37-7 C library for communicating with GPS devices libice6 2:1.0.4-1 X11 Inter-Client Exchange library libsm6 2:1.0.3-2 X11 Session Management library libxaw7 2:1.0.4-2 X11 Athena Widget library libxmu6 2:1.0.4-1 X11 miscellaneous utility library libxp6 1:1.0.0.xsf1-2 X Printing Extension (Xprint) client library libxpm4 1:3.5.7-1 X11 pixmap library libxt6 1:1.0.5-3 X11 toolkit intrinsics library python-gps 2.37-7 Python interface to gpsd and testing environment python-support 0.8.4lenny1 automated rebuilding support for Python modules python2.4 2.4.6-1+lenny1 An interactive high-level object-oriented language (versio python2.4-minimal 2.4.6-1+lenny1 A minimal subset of the Python language (version 2.4)
Then, to ensure that gpsd will actually run, configure the daemon with the following command:
~# dpkg-reconfigure gpsd
A dialog will appear with some questions that should be answered as follows:
Start gpsd automatically on boot? Yes Device the GPS receiver is attached to: /dev/ttyS0 Should gpsd handle attached USB GPS receivers automatically? No Options to gpsd: -b -n
Explanation of the two options:
Afterwards, these settings are saved in /etc/default/gpsd and the daemon is started automatically.
The source code for gpsd includes a PHP script, gpsd.php, that can be used to generate a skyview webpage for the GPS. For example, see this gpsd webpage. It requires php and php-gd to run. The first time it is invoked, a file called gpsd_config.inc is created containing configuration information that should be modified accordingly.
4. Firmware reconfig
For accurate time keeping with the Garmin GPS 18 LVC, both the PPS signal and the NMEA 0183 data are necessary. This is for two different reasons. First, the PPS signal itself does not contain time and date information − this is found only in the NMEA 0183 data (along with latitude and longitude information). Second, it would be possible to synchronize the NTP daemon on the start of the NMEA 0183 data alone, except that this information is always sent 0.2 seconds too late. Therefore, both are required.
Once the GPS device has been connected to the serial port and gpsd has been started, check the configuration of the port with the stty utility:
~$ stty < /dev/ttyS0 speed 4800 baud; line = 0; intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>; werase = <undef>; lnext = <undef>; flush = <undef>; min = 1; time = 0; -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke ~$ _
Among other things, this shows the speed at which gpsd is communicating with the GPS device: 4800 baud.
It should now possible to check the output of the GPS device with the gpspipe -r command − a utility that comes with the gpsd-clients package. In the beginning, the output from the device looks much like this:
$GPRMC,160516,A,5209.2521,N,00428.9913,E,000.0,140.8,270108,001.0,W*67 $GPGGA,160516,5209.2521,N,00428.9913,E,1,03,4.7,,M,46.8,M,,*65 $GPGSA,A,2,01,,,,,,17,20,,,,,4.8,4.7,*17 $GPGSV,3,1,11,01,28,046,38,04,15,301,00,11,52,152,00,12,03,357,00*7B $GPGSV,3,2,11,13,10,201,00,14,01,035,00,17,44,274,32,20,85,276,40*74 $GPGSV,3,3,11,23,45,183,00,31,23,072,00,37,00,000,00*41 $PGRME,27.9,M,,M,31.2,M*0C $GPGLL,5209.2521,N,00428.9913,E,160516,A*29 $GPVTG,141,T,142,M,000.0,N,0000.0,K*7D $PGRMV,0.0,0.0,*72 $PGRMF,440,57930,270108,160516,14,5209.2521,N,00428.9913,E,A,1,0,141,\ 5,1*2B $PGRMB,,,,,,K,,,*2D $PGRMM,WGS 84*06
This may seem fine, but the problem is that the device is only sending this information once every two seconds, as opposed to once every second as is required for ntpd. The device is simply not capable of sending its data any faster, so the objective here is to make it send less data. Apparently, the Garmin GPS 18 LVC sends this amount of information because certain features have been enabled beyond its factory defaults. Consequently, the problem can be solved simply by returning the unit to its factory defaults. To achieve this, the appropriate commands must be sent to the serial port to which the GPS device is attached. But first, start by installing one new package:
~# apt-get install tofrodos
Only this one package is installed as a result:
tofrodos 1.7.8.debian.1-1 Converts DOS <-> Unix text files, alias tofromdos
Then create a file, called ~/send.txt, with just this single line:
This is the command that will return the device to its factory defaults.
Next, after saving the file it is necessary to convert it to DOS text format:
~# unix2dos ~/send.txt ~# _
Now send this commands to the serial port as follows:
~$ cat ~/send.txt > /dev/ttyS0
It is interesting to run gpspipe -r in another terminal to monitor the effects of the previous command in real time. When the command is executed, the output from the device should decrease markedly and begin repeating once every second, for example:
$GPRMC,235530,A,5209.2483,N,00428.9918,E,000.0,017.3,280108,001.0,W*65 $GPGGA,235530,5209.2483,N,00428.9918,E,1,05,2.3,,M,46.8,M,,*64 $GPGSA,A,2,08,,,15,,18,,,26,28,,,2.5,2.3,*10 $GPGSV,3,1,11,08,24,071,36,09,22,259,00,10,19,189,00,15,75,278,39*79 $GPGSV,3,2,11,17,13,120,00,18,28,311,41,19,02,009,00,22,00,335,00*7C $GPGSV,3,3,11,26,87,203,41,28,54,077,38,43,00,000,00*41
This is considerably less information than before.
5. NTP daemon
The last software package to install is the NTP daemon: ntpd. It must be configured both to receive timing information from gpsd, as well as to provide a service to NTP clients. Start by installing its associated Debian package:
~# apt-get install ntp
Two packages are installed as a result, including one dependency:
libcap1 1:1.10-14 support for getting/setting POSIX.1e capabilities ntp 1:4.2.4p4+dfsg-8lenny3 Network Time Protocol daemon and utility programs
After that, several edits to /etc/ntp.conf are required, starting with the addition of these lines:
server 0.debian.pool.ntp.org iburst dynamic server 1.debian.pool.ntp.org iburst dynamic server 2.debian.pool.ntp.org iburst dynamic server 3.debian.pool.ntp.org iburst dynamic server 127.127.28.0 minpoll 4 fudge 127.127.28.0 time1 0.183 refid NMEA server 127.127.28.1 minpoll 4 prefer fudge 127.127.28.1 refid PPS
These specific loopback addresses allow ntpd to access the two shared memory segments provided by gpsd. The refid names are arbitrary, but descriptive, while the value for the time1 parameter − 0.183 − is to compensate for the offset of the NMEA 0183 signal. However, other systems will likely achieve better results with a slightly different value.
Next, allow local clients to have unlimited access:
# Clients from this (example!) subnet have unlimited access, # but only if cryptographically authenticated #restrict 192.168.123.0 mask 255.255.255.0 notrust restrict 192.168.1.0 mask 255.255.255.0 nomodify
This change allows all NTP clients in the entire 192.168.1.0 subnet to have unlimited access without requiring cryptographic authentication. However, because of the nomodify option they are still barred from modifying the state of the server. The network and netmask values should be modified accordingly.
Last, save the above changes and restart the NTP daemon to activate them:
~# /etc/init.d/ntp restart Stopping NTP server: ntpd. Starting NTP server: ntpd. ~# _
The GPS broadcast signal easily penetrates less dense material, such as plastic, but not higher density materials such as brick. Therefore, for a GPS receiver to function reliably, its antenna must be positioned where it has a relatively unobstructed view of as much of the sky as possible. This is important, because if the device is not able to receive a signal from at least one GPS satellite at all times, the stability of its clock signal will suffer considerably.
To this end, the Garmin GPS 18, with its internal antenna, is waterproof and was designed to continuously withstand weather conditions in most parts of the world. In the example below, however, the the device is located indoors and fixed to the inside of a plastic skylight. In this case the original 5 meter cable needed to be extended by only a few meters.
The Garmin GPS receiver shown above is attached to the inside of the skylight with a simple plastic car windshield mount that works with a strong suction cup. Since the receiver has an internal (female) screw thread underneath, this was used to fix it to the windshield mount after drilling a small hole through the center of the mount's platform.
However, as an occasional failure of the suction cup is inevitable, a safety device was improvised to catch its fall and prevent any damage. In this case, the safety device consists of an old coat hanger, covered with white heat-shrink tubing for aesthetic effect, and bent into a shape like an arched fishing rod with a T-section near its base for lateral stability. The lower vertical section, meant to counter the force of a fall, extends down into the cable conduit.
After the device has been reconfigured, positioned and connected, and all of the software has been up and running properly for a few minutes, use the following command to print a list of the peers and locally attached time sources known to the server, as well as a summary of their state. Here is an example:
~$ ntpq -p remote refid st t when poll reach delay offset jitter ============================================================================== -ntp0.nl.uu.net .PPS. 1 u 4 64 377 19.293 -3.809 0.083 -ntp1.nl.uu.net .PPS. 1 u 62 64 377 17.578 -3.404 0.240 -ntps1-0.cs.tu-b .PPS. 1 u 40 64 377 46.524 0.372 0.335 +ntps1-1.cs.tu-b .PPS. 1 u 52 64 377 46.309 0.430 0.308 xSHM(0) .GPS. 0 l 14 16 377 0.000 9.767 2.473 *SHM(1) .PPS. 0 l 13 16 377 0.000 0.000 0.001 ~$ _
The values for delay, offset and jitter are in milliseconds. For locally attached time sources the delay is always zero, while the jitter value for the GPS measurement pulse appears to be only a few microseconds (thousandths of a millisecond). Other systems may not achieve results that are quite this accurate, but they will still be an order of magnitude better than what can be expected with a radio time signal receiver.
Occasionally, things may get stuck, especially when the system boots up. This can be due to a communications problem between gpsd and the GPS device. For example, stty may show that the port speed has mysteriously changed to something other than 4800 baud, in which case it may not be enough to simply restart gpsd. A power cycle of the GPS device (in this case by momentarily removing the USB plug from its socket) followed by a gpsd restart may be the only solution. Seeing as the system is otherwise stable, a long-term solution may be to include a relay, operated through another serial port and controlled by a script that monitors the output from ntpq -p, and/or a second GPS device that ntpd can turn to in case the first one fails.
9. Further reading
10. Other NTP solutions