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:
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