Build you own stratum-1 NTP server for less than $100

Posted by Fred C (W6BSD) on Aug 26 2012

You can build a highly accurate Stratum-1 NTP Server for less than $100 using an old Wyse WinTerm (see picture), a GPS and a few electronic components.

The first thing you must do is replace the flash inside of the Wyse with a new flash with a real operating system. You can use an embedded version of Linux such as BusyBox, NetBSD, or FreeBSD with FlashBoot. On my Wyse WinTerm I installed OpenBSD and used the package flashrd to build an embeded version of OpenBSD.

I usually build my own OpenBSD flash, but you can use one of the pre-made flash distributions available on the flashrd site.

NTP Server using OpenBSD and a Garmin GPS18LVC

Cost detail

  • Wyse WinTerm V30-vx0 - $25 on eBay
  • Garmin GPS18LVC - $45 on eBay
  • A few wires, 2 resistors, 2 LED, 1 prototyping board, connectors - less than $9 at Fry's Electronics

Configuring your GPS

According to its manual, the Garmin GPS18LVC draws 60mA at 5.0V. Add a 20mA for the LEDs, a total of 80mA will be drawn from the USB port. A standard USB port is able to provide 500mA of power, therefore there is no concern that a standard USB port is able to provide power for our GPS and little board.

Here is the schematics I used to connect the Garmin GPS18LVC to the computer: Schematics

Connect the GPS to the serial port, and on a USB port. The only purpose of the USB port is to provide power (5V) to the GPS. On the Wyse WinTerm there is only one serial port, therefore the address will be /dev/cua00.

Once your GPS is connected to the Wyse the power LED should be on and after a few seconds the PPS indictor LED should flash once every second. By default the PPS is enabled on the Garmin GPS18LVC. If the PPS LED does not flash you can use the Windows based Garmin software to configure your GPS or simply use a serial terminal emulator.

On mine I used the command cu -4800 -l /dev/cua00 to connect to the GPS and verify that the configuration was fine. You can configure your GPS using the Garmin software, manually using cu and typing the commands directly on the console. You can also use a little script like the one I used to set the GPS with the right options. The advantage of using a script is that you can run it again if the GPS is reset to the factory defaults, or if you want to configure a second one.

from time import sleep
from serial import Serial

ser = Serial(port='/dev/cua00', baudrate=4800)
print "Set all NMEA sentence OFF"
ser.write("$PGRMO,,2\r\n")
print "response: " + ser.readline()[:-1]
print "Read PGRMC register"
ser.write("$PGRMCE,\r\n")
sleep(1)
print "Working settings: " + ser.readline()[:-1]
print "Writting new settings"
ser.write("$PGRMC,A,27.0,100,,,,,,A,5,1,2,4,\r\n")
sleep(1)
print "New saved setting:  " + ser.readline()[:-1]
print "Configuring NMEA sentence..."
#ser.write("$PGRMO,GPGCA,1\r\n")
ser.write("$PGRMO,GPRMC,1\r\n")
#ser.write("$PGRMO,GPGSA,1\r\n")

print "Configuration done."
print
print "Reading NMEA sentences from GPS receiver"
while True:
  print ser.readline()[:-1]

After configuring your device or after running the Python script the output of your GPS should be as follows. Where only the NMEA code $GPRMC is printed. The PPS LED situated on the prototyping board should continue to flash once every second. If the LED doesn't flash or the output is different try configuring your GPS again.

Also beware that the lines should be terminated by the sequence \r\n. If you are using a terminal emulator, make sure it is correctly configured to send the appropriate CR NL every time you hit the Enter key.

Example of GPS output after configuration:

$GPRMC,182723,A,3727.6138,N,12214.8548,W,000.0,031.6,260812,014.0,E*6F

It is important to remove as many messages returned by the GPS as possible, because the NTP driver uses the $ sign as the beginning of the second. At 4800 Baud it can take more than one second to print all the messages sent by the GPS.

Now that your GPS is correctly configured, you need to create a link named /dev/gps0 pointing to the serial port where your GPS is connected. The NTP driver can only handle devices named gpsn where n is the GPS number

bash# ln -s /dev/cua00 /dev/gps0
bash# ls -l /dev/gps0
lrwxr-xr-x  1 root  wheel  10 Jun 24 14:34 /dev/gps0 -> /dev/cua00

Configuring the NTP daemon

By default OpenBSD uses OpenNTPd to synchronize its clock. OpenNTPD is a simple, lightweight NTP server designed with security as a priority. Even though you can use OpenNTPD with a GPS, I have decided to use the NTP server from ntp.org, which provides better precision and more control.

To install NTP simply use the packages tools provided by OpenBSD.

bash# pkg_add ntp

To have NTP started at boot time you need to add the following line near the end of the file /etc/rc.conf.local

xntpd_flags="-p /var/run/ntpd.pid"

Then edit /etc/ntp.conf to add the GPS as a clock server. My configuration contains:

#
enable stats
statsdir /var/log/ntp
statistics loopstats peerstats clockstats
#
filegen peerstats file peerstats type day enable
filegen loopstats file loopstats type day enable
filegen clockstats file clockstats type day enable
logconfig =syncstatus +sysevents +syncall +clockall
logfile /var/log/ntp/log
driftfile /var/db/ntp.drift
#
leapfile /var/db/leap.ntp
#
server 127.127.20.0 mode 1 prefer
fudge 127.127.20.0 flag1 1 flag2 0
#
server 127.127.1.0                      # local clock
fudge 127.127.1.0 stratum 7             # local clock
#
restrict default kod limited nomodify notrap nopeer
restrict 127.0.0.1

The first lines of the configuration file, are for what to log where. The lines telling NTP to use a reference clock, the GPS in our case, are the first two lines starting with server 127.127... and fudge 127.127.... For more information on reference clocks you can check the page Reference Clock Support.

Our NTP server uses a GPS supporting the NMEA standard The address for the Generic NMEA GPS Receiver is 127.127.20.n where n specifies which GPS to use. You remember when we created the link /dev/gps0? The zero is the number that we are going to use here 127.127.20.0. mode 1 tells the driver to use the NMEA phrase $GPMRC to get the time reference from.

The second line starting with fudge followed by the driver address, passes some more configuration info to the driver.

flag1 1 Enable the use of the PPS signal.

flag2 0 Tell the driver to capture the pulse at the rising edge.

The following two lines starting with server 127.127.1.0 and fudge 127.127.1.0 configure the internal clock. This is important when other machines in your datacenter are synchronized to your NTP server and when having all the machines in sync is more important than the time accuracy. If your GPS has problems receiving the signal, or simply fails, your NTP server will use its internal clock to continue to provide the time to the client machines. The time may drift away from the "real" time but all the machines will drift the same way and they will all stay in sync.

The last line I want to talk about in this configuration file is the line starting with leapfile. The US NIST publishes a file which contains a table of past and upcoming leap seconds. This file can be used by NTP to become aware of leap second announcements. Part of the job of a stratum-1 server is to advertise pending leap seconds during the day prior to the event. You can download this file at ftp://tycho.usno.navy.mil/pub/ntp/

More information on the leap seconds: (Leap second, Using the NIST Leap Second File)

Check if your NTP server is working

The best way to verify that your NTP server is working well is to use the ntpq or ntpdc utility. The option -c peers displays informations about the peers.

$ ntpdc -c peers
     remote           local      st poll reach  delay   offset    disp
=======================================================================
*GPS_NMEA(0)     127.0.0.1        0   64  377 0.00000 -0.000736 0.03931
=LOCAL(0)        127.0.0.1        7   64    0 0.00000  0.000000 3.99217

You can also use the option -c sysinfo which will print a variety of system state variables.

$ ntpdc -c sysinfo
system peer:          GPS_NMEA(0)
system peer mode:     client
leap indicator:       00
stratum:              1
precision:            -18
root distance:        0.00000 s
root dispersion:      0.00662 s
reference ID:         [GPS]
reference time:       d3e9704b.f5d0d41e  Wed, Aug 29 2012 21:53:31.960
system flags:         auth monitor ntp kernel stats
jitter:               0.002462 s
stability:            0.000 ppm
broadcastdelay:       0.000000 s
authdelay:            0.000000 s

NTPD Gate: Jitter Graph


 NTP      OpenBSD      Embedded      Sys Admin