Adding a GPS time source to NTP in Fedora
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.
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.
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.
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
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
.
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.
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.