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.
GPS -- Global Positioning Service, operated by the USA Department of Defense. The USSR and successors operates their own version called GLONASS, the European Union has started on the Galileo system, and China, India and Japan are also developing their own systems.
NMEA --
National Marine Electronics Association. Their standard 0183 defines
a protocol whereby sonar, gyrocompass, GPS and other sensors and ship
control devices can communicate. NMEA-0183 has become the de facto
standard for output from GPS receivers. The term NMEA Sentence
refers to a communications packet in this protocol. See
Why GPSes suck, and what to
do about it by Eric S. Raymond (2009-02-23) for criticisms of this
standard.
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.
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:
KERNEL=="ttyUSB*" -- We know that this device comes out as /dev/ttyUSB$number, but coldplug events appear in an arbitrary order, so the minor number varies from one boot to the next, and recently active minor numbers are not re-used if you remove and reconnect the device. So we need to make a consistent symbolic link to the real TTY name. This rule field attracts the symlink to the actual TTY rather than the containing USB object.
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303" -- These identify the Prolific Technologies 2303 serial to USB interface, not the MediaTek chip behind it. That's not a problem if you have only one pl2303 connected, but the ideal is for the USB product ID to refer to the device as a whole, and also to include the serial number, in case several are connected at the same time. That's unlikely for a GPS receiver, but printers, modems and pointing devices are more likely to be prolific.
SYMLINK+="gps0" -- Appends the gps0 name to the list of symbolic links that have to be made to the underlying device. Udev rules are performed in lexical order, merging several directories, and I found that the symlink was ignored if I put it in a low numbered rule file. This implies that something in the middle, like 50 to 60, wipes the symbolic link list for TTYs. If I find it, I will send in a bug report.
MODE="644" -- The world readable mode was useful for testing, but since only gpsd is supposed to be reading, I probably should change this.
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.
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:
helpfultransformation of the data, vs. -raw or cooked, which causes fragments of previously sent sentences to reappear.
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.
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 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:
Hosts that reboot for maintenance or which otherwise restart chronyd. It saves the history of its superior servers and of its realtime clock, and can pick up where it left off with little disruption, much better than ntpd.
Hosts that sleep or turn off power, like a home system. Chronyd uses the realtime clock, and its measured frequency error, to estimate the time when it wakes, so it starts up with fairly good synchronization, a lot better than ntpd.
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.
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.
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.
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.
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.
MR-350 (without P) lacks PPS.
MR-350P (not S4) has PPS and a SiRF Star III chipset, which is said to have good sensitivity under leaf or indoors. One vendor sells it for US $54 (fulfilled by Amazon).
MR-350P-S4 has PPS and a SiRF Star IV chipset. Some forum posters say SiRF Star IV is less sensitive than the Star III, while others say it is as good or better. A different vendor sells it for $46 (fulfilled by Amazon).
All of these are for bulkhead mounting: drill a hole in your boat's or truck's roof and use the provided nut, washer and gasket to attach the MR-350P. The cable has a proprietary DIN connector. You need to get one of the two adapter cable types, sold separately for $15 to $45 from various vendors. One is for USB and I believe I've seen forum postings that PPS emulation over USB is not provided. One has a Y connector with a DB-9 serial connector for data, definitely with PPS, and a PS/2 DIN connector for power; in the 21st century we're going to rely on a PS/2 to USB converter to make that work.
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.
I would like to commend GlobalSat USA for their excellent and patient customer support, and particularly Jesse Cruz on the tech support desk.
Whatever was causing the GPS receiver to come up with channels=0, I wish that would stop happening, and I wish I knew a simple and repeatable way to un-choke the receiver that I could describe to other users. At least I eventually got it working. See the next section for a NMEA sentence that did a factory reset for me in the Bermuda Triangle, and has a chance (never tested) of breaking loose a stuck receiver.
I wish that CS/RI were connected to the USB interface and that it were used for PPS signalling, with ZDA sentences to announce the timing. This is a zero cost change in the circuit board, and probably a very simple firmware change.
For existing receivers without CS/RI signalling on USB, I wish that ZDA sentences could be enabled anyway. They should be sent immediately after the RF backend brings up CS/RI, so there is a small and consistent offset from the time that the ZDA sentence will report, until the byte stream begins arriving on the host. The number of bytes in each ZDA sentence should be the same despite leading or trailing zeroes in particular fields, so the end will also have a consistent timing.
I wish that a unique USB vendor and product ID could be assigned to the GlobalSat ND-105C (and incremented for each firmware revision with an effect visible to the software). Also useful would be to provide the device's serial number in the iSerial field, in case of multiple similar devices.
Is channels=0 the only culprit for choke mode? I am unable to get it back into channels=0 mode. Although a PSRF104 message can set off a factory reset (ResetCfg bitmap = 0x8), a warm or tepid reset (4 or 2) does not stop nav fixes, whereas they are supposed to clear the ephemeris, which would take 30 seconds to replace.
If you send SIGHUP to gpsd will it reopen the chrony socket? If so, change unit files to use this. What it does:
success.
So I think HUP isn't going to be effective in coordinating gpsd and chronyd.
How long after a factory reset (wipe almanac) does it take to get fixes? A long time. The GPS receiver was silent for at least 60 minutes. It finally coughed up after about 80 minutes. This is the message I sent to do the factory reset, including my coordinates and time even though not used:
$PSRF104,34.01312,-118.43585,53,0,86212.8033239841,1856,12,8*25\r\n
It is possible (though untested) that other people could send the same message to cause a factory reset, since the reset bitmask (8) says that the given coordinates are not to be used, and the documentation suggests that the receiver is incapable of using them after a factory reset. Be sure to set the TTY mode in advance. It's very likely that the message will be ignored unless it ends with \r\n. In Bourne shell, to produce a \r do this, with $ and single quotes as shown and no \n:
echo $'$PSRF104,34.01…12,8*25\015' > /dev/gps0
Unplug and plug, what gets lost? When the receiver was unplugged for about 10 secs and then replugged, within 2 seconds it was sending navigation fixes and was using all but one of the satellites it had previously.
See if I can enable ZDA sentences. It failed to turn off/on GSV sentences as a positive control. Didn't affect ZDA either, nor VTG, which all SiRF chips are supposed to support. The GlobalSat ND-105C has a MediaTek chipset, and I'm beginning to suspect that it ignores PSRF103 control sentences, as well as not supporting ZDA, which only 3 SiRF variants can produce.