Valid HTML 4.01 Transitional

GPS Clock Source

James F. Carter <jimc@math.ucla.edu>, 2015-07-28

I have tried to set up non-network-based time service using an inexpensive commercial USB GPS receiver, the GlobalSat ND-105C. The reader interface is gpsd by Eric S. Raymond (lead developer), and timing is by chrony by Richard P. Curnow. Unfortunately the operative word here is tried.

The reader's first question is going to be, Why? One lame answer is that if my internet connection goes down, I will still have accurate timekeeping. Of course the followup is, if your net is down you have a lot bigger problems than a few PPM drift in your machine's clock. Chrony knows the relative rates of GPS time, NTP time, the realtime clock, and the HPET (the kernel's clocksource on most Intel-type systems), and will make the system time run very close to the correct rate even without a connection to the outside world, if configured to do so.

The real reason is, because I can. I have no operational requirement or justification for this feature, but it's the ultimate geek toy.

Jargon

GPS Receiver

I'm using the GlobalSat ND-105C, available inexpensively on Amazon.com. It uses a MediaTek chipset (type unknown, can use SiRF binary protocol) and a Prolific Technologies 2303 serial to USB interface. Physically it has a micro-USB male connector and the sales pack includes a short (15cm) female micro-USB to male type A cable. It can be used for testing on an Android cellphone. The Samsung Galaxy S5 has a water resistant door over the micro-USB port, and the ND-105C will fit (just barely) with the door open.

You plug the ND-105C into a USB port, and the host loads the driver for the Prolific 2303. This is pl2303 and usbserial on Linux, and the sales pack includes a mini-CD with a Windows driver. The ND-105C starts producing NMEA sentences, which report the location and other data which the device has received from the satellites. More features are available via the SiRF binary protocol, but all that I needed was in the NMEA data stream.

For most people this process goes smoothly if slowly. If the receiver has been in storage for weeks or months, as when it is first purchased, it will need to try satellite frequencies and orthogonal codes at random, before it finds the first satellite. It will then take 30 seconds to download that satellite's ephemeris (orbit parameters), but also 12.5 minutes to download the almanac. The latter has simplified orbits for all the satellites and all of them send out the same almanac. Once this data comes down, the device can go right to all the visible satellites, and it will start sending out navigation fixes. In one test after a factory reset this process took 80 minutes, and I'm sure that's not the slowest time.

The ephemeris is valid for four hours and is updated every two hours. The almanac lasts at least a week and probably quite a bit more; it is updated daily. If the receiver has been powered off for several hours, it will need to download ephemerides for the satellites it will be using, taking 30 seconds. However, empirically it seems that the receiver is willing to use an outdated ephemeris if not too old, so the 30 second delay is only seen for longer downtimes. During normal operation the receiver downloads newly posted versions of these tables without interrupting navigation.

However, my house is the Bermuda Triangle for GPS receivers. It reported that it could find no satellites, despite running undisturbed for two days. The result was the same on desktop Linux, Windows and Android, and despite interventions such as sending a factory reset command.

How I got it out of this mode: One NMEA type 104 message did it; this is titled LLA Navigation Initialization. The content was like this, except the time was different and the correct checksum was appended.

$PSRF104,34.01312,-118.43585,53.0,0,50034200,1855,12,1*FF\r\n

Interpretation of fields:

How it got into this mode: I have no idea, particularly since GlobalSat customer service found that one receiver worked for them but it subsequently failed for me. I suspect that the number of channels got set to 0, but not by any messages I sent it, except for subsequent unsuccessful tries to get it to fail on command. Very strange: For most people, the receiver starts up by itself. For me, two different devices showed the same behavior. I sent one (RMA) to GlobalSat customer service, and it worked for them, but didn't work for me when they sent it back.

udev Rules

When a device is hotplugged, or coldplugged (at boot), the udev daemon is aware and performs some setup steps. For the GPS receiver I have this rule, in /etc/udev/rules.d/78-gpsJ.rules . It creates a symbolic link /dev/gps0 to the serial TTY.

KERNEL=="ttyUSB*", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="gps0", MODE="644"

Explanation of fields:

It's also common for gpsd to be started by the hotplug event, and SuSE provides /usr/lib/udev/rules.d/51-gpsd.rules to do this. But in my case, starting needs to be coordinated with chronyd, which provides a socket that gpsd will open, so in /etc/sysconfig/gpsd I set GPSD_STARTBYUDEV="no" to suppress this behavior.

TTY Line Mode

Beware, if you try to read the TTY directly, the default line parameters produce very confusing garbage. I'm sure the TTY driver is involved but I don't see why. You need to do:

stty -F /dev/gps0 4800 cs8 -cstopb -parenb raw

Explanation of options:

Gpsd will set the line parameters itself, and it knows the different parameters needed by different receivers, but if you are testing with scripts or command line tools, you definitely need to set the line mode explicitly.

Global Positioning System Daemon (gpsd)

I have gpsd by Eric S. Raymond (lead developer), version 3.5, from the OpenSuSE Build Service. gpsd is designed to auto-detect the type of GPS receiver and to use its best protocol. The command line is simply:

/usr/sbin/gpsd -n /dev/gps0

Multiple clients can then connect to gpsd's socket and/or TCP port and receive a sanitized version of the GPS data stream. There are also multiple high precision interfaces from gpsd out to ntpd or chronyd.

The -n option means that gpsd should start reading the receiver immediately, not waiting for a client connection. This is necessary for feeding data to chronyd or ntpd, which do not make a normal client connection.

For testing, the gpsd documentation recommends using xgps from the gpsd-clients package on SuSE. It shows a list of satellites with their signal strengths (SNR), a graphical plot of their locations in the sky, a debug dump of the digested NMEA sentences, and the interpreted GPS location, time, velocity and errors.

Chronyd Timekeeping Daemon

Chronyd by Richard P. Curnow is a timekeeping daemon which uses the NTP protocol (RFC 5905) to keep synchronized with superior time servers. It is a modern revision and rewrite of ntpd by David Mills. It is particularly suited to these circumstances:

Chrony has three special interfaces to receive input from timekeeping daemons such as gpsd. Pick the configuration line that is going to work best with your clock source, and include it in /etc/chrony.conf.

refclock SHM 0 offset 0.308 refid NMEA

This driver watches for gpsd to place navigation fixes in a shared memory segment; it is specifically interested in the time component. Unfortunately there is a large and not particularly stable delay after the satellites are measured, until the result is sent by the GPS receiver and then is posted by gpsd. This is adjusted in the offset parameter, units of seconds. chronyc -h localhost sourcestats will report that the NMEA source has a particular offset. From repeated reports estimate a consensus offset and add that to the refclock offset; the reported offset should become zero (plus-minus a discouraging amount).

The refid is an identifier of up to 4 ASCII bytes. The default for this driver is SHM0. I called it NMEA because the data source is NMEA sentences from the GPS receiver.

refclock SHM 1 offset 0.0 refid PPS

This driver similarly watches a different shared memory segment. It is intended for a reference clock that communicates on a serial TTY (COM port). The clock drops and reenables Carrier Sense or Ring Indicator (gpsd auto-detects which), and then sends a ZDA NMEA sentence telling when it did so, using time according to the satellites. Gpsd can determine very precisely what the system clock said when CS/RI came up, and chrony therefore knows how much to adjust the system clock so it matches GPS time.

Unfortunately the USB TTY has nothing equivalent to CS/RI, so gpsd has nothing to put in the shared memory segment when the clock source is a USB GPS receiver. More precisely, most RF backends have a serial output which may or may not include PPS on CS/RI, and the Prolific PL2303 USB to serial interface has an input for these lines, but these pins are not connected. Some people have succeeded in sawing the cover off a GPS receiver and making a working connection. If this is done, gpsd can interpret the result accurate to 1 msec, assuming the receiver can be induced to produce ZDA sentences, which is rare.

refclock SOCK /var/run/chrony.gps0.sock offset 0.0 refid SOCK

This driver creates the socket whose name is given, and reads it. Gpsd opens the socket and sends the same information that it's putting in SHM 1. But the data structure has nanosecond precision, so if the clock itself plus the various software has sub-microsecond precision and stability, the SOCK driver can receive this high quality data, which the SHM 1 driver could not do.

Gpsd will try to write on a socket named after the basename of the TTY it is reading; e.g. if it is reading /dev/gps0 it wants to write on /var/run/chrony.gps0.sock . For a network connection the remote hostname is used in the socket name. Chrony creates the socket, so gpsd needs to start after chrony starts. A HUP signal to gpsd will induce it to reopen the socket, as well as the TTY, except there are complications because it has dropped privileges, so the reopening fails.

Similarly to SHM 1, USB GPS receivers do not deliver the needed information and gpsd never writes anything on the socket.

GPS Timing Performance

In short, pretty bad. I ran for almost 12 hours, and every 5 minutes I did chronyc -h localhost sourcestats. Relative to a nearby stratum 1 source, whose offset varied mostly in ±2 msec, the GPS receiver's offset ranged from -22 to 77 msec. It seemed to vary almost randomly, with possible patterns being hard to discern. Chrony always marks it defective. Obviously this experiment has failed.

So where can I go from here? It's fairly clear that if I want to make this work, a generic USB GPS device will not do, and other authors agree with me. So I looked in the gpsd hardware compatibility list for receivers with PPS capability.

Of the receivers that are not discontinued, not special order, and not OEM modules, that is, of receivers I could actually buy, the GlobalSat MR-350 family is the only one available on reasonable terms.

I think I'm going to give this project a rest for a while. When I come back to it, the GlobalSat MR-350P would be the next device to try.

Kudos

I would like to commend GlobalSat USA for their excellent and patient customer support, and particularly Jesse Cruz on the tech support desk.

Wish List

Items to be Tested