Adding a GPS time source to NTP in Fedora

The tie-wrap makes the difference!

I recently connected a Garmin GPS 18 LVC GPS receiver to my computer used for radios and communications. This was a cheap (~$60) way to add an additional time source to NTP. Everything you really know is in this excellent guide. What lies here is largely based off that guide, so read it too.

There were a few differences, mostly because I use Fedora and the aforementioned guide uses Debian/Ubuntu.

Below are my notes.

Wiring

First of course is wiring to the serial port. I had a real one available, but I suspect a USB to RS232 dongle would work (perhaps at a loss of accuracy). The guide from RJ Systems spells out all the details. In short, you need to wire it this way:

Garmin       DB-9

Yellow  ->   1       (PPS -> DCD)
White   ->   2       (RX)
Green   ->   3       (TX)
Black   ->   5       (Ground)

Red                  +5 V

As suggested by the guide, I’m getting my power from a USB port. You could get yours plenty of other ways.

Serial Port Configuration

Following the source material, install setserial:

# dnf install setserial

Fedora doesn’t give you a /etc/init.d/setserial, so just manually setup the port for now:

# setserial /dev/ttyS0 uart 16550A port 0x03f8 irq 4 baud_base 115200 spd_normal skip_test low_latency

Note your settings may be different. The settings above are for a standard UART on port 0 (aka COM1). If you are not using /dev/ttyS0, be sure and adjust all following commands accordingly.

Now is a good time to see if the Garmin is spitting out NMEA sentences. Fire up your favorite serial terminal (you have one, right), in my case minicom. Connect to /dev/ttyS0, set the port to 4800 N81, and no hardware flow control. You should see $GP… lines scroll across your console.

GPSD

Once you have connectivity working, install GPSD and friends:

# dnf install gpsd gpsd-clients

Edit /etc/sysconfig/gpsd:

# Options for gpsd, including serial devices
OPTIONS="-b -n /dev/ttyS0"
# Set to 'true' to add USB devices automatically via udev
USBAUTO="false"

Start GPSD and see if it’s receiving data:

# systemctl start gpsd
# gpspipe -r

Firmware Reconfiguration

Tell the Garmin to send less data, so we get updates close to once-a-second. This setting doesn’t seem to persist, so you will likely have to do this every time you power cycle it.

# echo -e "$PGRMO,,4\r\n" > /dev/ttyS0

See the RJ Systems guide for a more detailed explanation. I have simplified their instructions by using echo.

NTP

Last, we can configure ntp:

# dnf install ntp

As systemd continues to gobble up other daemons, you will find that Fedora by default uses “chrony” for time synchronization. I’m not sure if chrony supports external clocks, so let’s just turn it off:

# systemctl stop chronyd.service
# systemctl disable chronyd.service

Edit /etc/ntp.conf, appending these lines:

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

restrict w.x.y.z mask 255.255.255.0 nomodify

Be sure and adjust the restrict line to reflect your network, or just leave it out if you don’t want to serve the time. Note that if you do, you will also need to open up UDP/123 in firewalld.

Ok, we should be done, start up ntp:

# systemctl start ntpd.service

Now lets watch ntp’s status:

# watch -n 1 "ntpq -p"

After a few seconds you should see the last two lines offset and jitter values move around.

You should see something like this:

# ntpq -p
	 remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+ntp.wdc1.us.lea 129.6.15.28      2 u   45   64   17  148.933  -12.608   0.789
-173.44.32.10    164.244.221.197  2 u   46   64   17  118.766   -1.097   0.761
-biisoni.miuku.n 204.2.134.162    3 u   46   64   17   85.313   -2.554   0.660
+131.107.13.100  .ACTS.           1 u   47   64   17  156.412  -19.010   4.152
xSHM(0)          .NMEA.           0 l    7   16  377    0.000  -436.01  77.622
*SHM(1)          .PPS.            0 l    6   16  377    0.000   -0.090   0.307

So there you go. In reality, your clock probably isn’t much more accurate now than it was before… unless you loose Internet connectivity.

Next Steps

You may have noticed that I didn’t enable GPSD or NTPD at boot. Since Fedora’s setserial package doesn’t look like it will configure the port at boot, I have left this out for now.

A start-up script would probably look something like this:

setserial /dev/ttyS0 uart 16550A port 0x03f8 irq 4 baud_base 115200 spd_normal skip_test low_latency
systemctl start gpsd.service
systemctl start ntpd.service
echo -e "$PGRMO,,4\r\n" > /dev/ttyS0

Also, beware that chrony was disabled, so if you reboot and do not manually start ntpd as shown, you will not be syncing to any clocks.