chrony with gpsd and pps

5.4k views Asked by At

On my PC I want to feed chrony from GPS. For this, I installed gpsd and pps-tools. I have a GPS connected to the serial port /dev/ttyS0 and the PPS is connected to the DCD input. Apparently, the PPS pulses are received correctly:

$ sudo ppscheck /dev/ttyS0
# Seconds  nanoSecs   Signals
 1646915383.000347816 TIOCM_CD
 1646915383.100323649
 1646915384.000213974 TIOCM_CD
 1646915384.100172453
...

so far so good. Also, the data from the GPS module seems to be received correctly. I verify this using sudo gpsmon /dev/ttyS0. It appears as the $GPRMC sentence is successfully received and that the data was valid. A time could be extracted and the PPS was detected also:

┌──────────────────────────────────────────────────────────────────────────────┐
│Time: 2022-03-10T12:31:10.000Z   Lat: 46 xx.xxxxxx' N   Lon:   7 xx.xxxxxx' E │
└───────────────────────────────── Cooked TPV ─────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ GPRMC                                                                        │
└───────────────────────────────── Sentences ──────────────────────────────────┘
┌───────────────────────┌─────────────────────────┌────────────────────────────┐
│ SVID  PRN  Az El SN HU│Time:     123110         │Time:                       │
│                       │Latitude:   46xx.xxxxx N │Latitude:                   │
│                       │Longitude:   7xx.xxxxx E │Longitude:                  │
│                       │Speed:    000.0          │Altitude:                   │
│                       │Course:   000.0          │Quality:       Sats:        │
│                       │Status:   A        FAA:  │HDOP:                       │
│                       │MagVar:   000.0E         │Geoid:                      │
│                       └───────── RMC ───────────└─────────── GGA ────────────┘
│                       ┌─────────────────────────┌────────────────────────────┐
│                       │Mode:    Sats:           │UTC:           RMS:         │
│                       │DOP H=     V=     P=     │MAJ:           MIN:         │
│                       │TOFF:  0.132531938       │ORI:           LAT:         │
│                       │PPS:  0.000246686        │LON:           ALT:         │
└──────── GSV ──────────└────── GSA + PPS ────────└─────────── GST ────────────┘

so far, so good. I would like to run gpsd now such that chrony can get the time from it. Here the trouble begins. I test gpsd as follows `

gpsd:INFO: launching (Version 3.23.1, revision 3.23.1)
gpsd:IO: opening IPv4 socket
gpsd:SPIN: passivesock_af() -> 3
gpsd:IO: opening IPv6 socket
gpsd:SPIN: passivesock_af() -> 4
gpsd:INFO: listening on port gpsd
gpsd:PROG: NTP: shmat(0,0,0) succeeded, segment 0
gpsd:PROG: NTP: shmat(1,0,0) succeeded, segment 1
gpsd:PROG: NTP: shmat(2,0,0) succeeded, segment 2
gpsd:PROG: NTP: shmat(3,0,0) succeeded, segment 3
gpsd:PROG: NTP: shmat(4,0,0) succeeded, segment 4
gpsd:PROG: NTP: shmat(5,0,0) succeeded, segment 5
gpsd:PROG: NTP: shmat(6,0,0) succeeded, segment 6
gpsd:PROG: NTP: shmat(7,0,0) succeeded, segment 7
gpsd:PROG: successfully connected to the DBUS system bus
gpsd:PROG: shmget(0x47505344, 26712, 0666) for SHM export succeeded
gpsd:PROG: shmat() for SHM export succeeded, segment 8
gpsd:INFO: stashing device /dev/ttyS0 at slot 0
gpsd:PROG: no /etc/gpsd/device-hook present, skipped running ACTIVATE hook. No such file or directory
gpsd:INFO: SER: opening read-only GPS data source type 2 at '/dev/ttyS0'
gpsd:IO: SER: fusercount: path /dev/ttyS0 fullpath /dev/ttyS0 cnt 1
gpsd:IO: SER: fd 6 set speed 115200(4098)
gpsd:INFO: SER: fd 6 current speed 115200, 8N1
gpsd:IO: SER: open(/dev/ttyS0) -> 6 in gpsd_serial_open()
gpsd:PROG: Probing "Garmin USB binary" driver...
gpsd:PROG: Probe not found "Garmin USB binary" driver...
gpsd:PROG: Probing "GeoStar" driver...
gpsd:PROG: Sent GeoStar packet id 0xc1
gpsd:PROG: Probe not found "GeoStar" driver...
gpsd:PROG: Probing "Trimble TSIP" driver...
gpsd:IO: SER: fd 6 set speed 9600(13)
gpsd:INFO: SER: fd 6 current speed 9600, 8O1
gpsd:IO: SER: fd 6 set speed 115200(4098)
gpsd:INFO: SER: fd 6 current speed 115200, 8N1
gpsd:PROG: Probe not found "Trimble TSIP" driver...
gpsd:PROG: Probing "iSync" driver...
gpsd:IO: SER: fd 6 set speed 9600(13)
gpsd:INFO: SER: fd 6 current speed 9600, 8N1
gpsd:IO: SER: fd 6 set speed 115200(4098)
gpsd:INFO: SER: fd 6 current speed 115200, 8N1
gpsd:PROG: Probe not found "iSync" driver...
gpsd:PROG: no probe matched...
gpsd:INFO: gpsd_activate(2): activated GPS (fd 6)
gpsd:PROG: NTP:PPS: using SHM(0)
gpsd:PROG: NTP:PPS: using SHM(1)
gpsd:PROG: PPS:/dev/ttyS0 connect chrony socket failed: /run/chrony.ttyS0.sock, error: -2, errno: 111/Connection refused
gpsd:PROG: KPPS:/dev/ttyS0 checking /sys/devices/virtual/pps/pps1/path, /dev/ttyS0
gpsd:INFO: KPPS:/dev/ttyS0 RFC2783 path:/dev/pps1, fd is 7
gpsd:INFO: KPPS:/dev/ttyS0 pps_caps 0x1133
gpsd:INFO: KPPS:/dev/ttyS0 have PPS_CANWAIT
gpsd:INFO: KPPS:/dev/ttyS0 kernel PPS will be used
gpsd:PROG: PPS:/dev/ttyS0 thread launched
gpsd:INFO: PPS: activated /dev/ttyS0 ntpshm_link_activate(): Clock
gpsd:INFO: stashing device /dev/pps0 at slot 1
gpsd:PROG: no /etc/gpsd/device-hook present, skipped running ACTIVATE hook. No such file or directory
gpsd:ERROR: SER: stat(/dev/pps0) failed: No such file or directory(2)
gpsd:ERROR: initial GPS device /dev/pps0 open failed
gpsd:INFO: KPPS:/dev/ttyS0 kernel PPS timeout 4:unknown error
gpsd:INFO: KPPS:/dev/ttyS0 kernel PPS timeout 4:unknown error
gpsd:INFO: KPPS:/dev/ttyS0 kernel PPS timeout 4:unknown error
gpsd:INFO: running with effective group ID 18
gpsd:INFO: running with effective user ID 65534
gpsd:INFO: startup at 2022-03-10T12:35:52.000Z (1646915752)
gpsd:PROG: KPPS:/dev/ttyS0 assert  1646915753.000208807, sequence: 1, clear   0.000000000, sequence: 0 - using: assert
gpsd:PROG: KPPS:/dev/ttyS0 Assert cycle: 1646915753000208, duration: 0 @  1646915753.000208807
gpsd:RAW: PPS:/dev/ttyS0 Assert pps-detect changed to 1
gpsd:PROG: PPS:/dev/ttyS0 Assert cycle: 1646915753000208, duration: 0 @  1646915753.000208807
gpsd:PROG: PPS:/dev/ttyS0 Assert ignored missing last_fixtime
gpsd:PROG: KPPS:/dev/ttyS0 assert  1646915753.000208807, sequence: 1, clear   1646915753.100149920, sequence: 1 - using: clear
gpsd:PROG: KPPS:/dev/ttyS0 Clear cycle: 99941, duration: 99941 @  1646915753.100149920
gpsd:RAW: PPS:/dev/ttyS0 Clear pps-detect changed to 0
gpsd:PROG: PPS:/dev/ttyS0 Clear cycle: 99941, duration: 99941 @  1646915753.100149920
gpsd:PROG: PPS:/dev/ttyS0 Clear ignored missing last_fixtime
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.130428717 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:INFO: reconnection attempt on device 1
gpsd:PROG: no /etc/gpsd/device-hook present, skipped running ACTIVATE hook. No such file or directory
gpsd:ERROR: SER: stat(/dev/pps0) failed: No such file or directory(2)
gpsd:ERROR: /dev/pps0: device activation failed, freeing device.
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.131202895 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.132038783 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:IO: SER: gpsd_next_hunt_setting(6) retries 0 diff 0
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.132776939 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:IO: SER: gpsd_next_hunt_setting(6) retries 1 diff 0
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.133566515 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:IO: SER: gpsd_next_hunt_setting(6) retries 2 diff 0
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.134296808 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:IO: SER: gpsd_next_hunt_setting(6) retries 3 diff 0
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.135119824 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type -1
gpsd:IO: SER: gpsd_next_hunt_setting(6) retries 4 diff 0
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915753.135905236 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:PROG: switching to match packet type 1: $GPRMC,123553,A,46xx.xxxxx,N,7xx.xxxxx,E,000.0,000.0,100322,000.0,E*70\x0d\x0a
gpsd:PROG: switch_driver(NMEA0183) called...
gpsd:PROG: selecting NMEA0183 driver...
gpsd:INFO: /dev/ttyS0 identified as type NMEA0183, 1 sec @ 115200bps
gpsd:RAW: raw packet of type 1, 72:$GPRMC,123553,A,46xx.xxxxx,N,7xx.xxxxx,E,000.0,000.0,100322,000.0,E*70\x0d\x0a
gpsd:IO: <= GPS: $GPRMC,123553,A,46xx.xxxxx,N,7xx.xxxxx,E,000.0,000.0,100322,000.0,E*70
gpsd:DATA: NMEA0183: merge_ddmmyy(100322) sets year 2022
gpsd:RAW: NMEA0183: merge_ddmmyy(100322) 2 10 122
gpsd:DATA: NMEA0183: GPRMC: registers fractional time  123553.000000000
gpsd:DATA: NMEA0183: RMC: ddmmyy=100322 hhmmss=123553 lat=46.95 lon=7.44 speed=0.00 track=0.00 mode=2 var=nan status=0
gpsd:DATA: NMEA0183: GPRMC newtime is  1646915753.000000000 = 2022-03-10T12:35:53.000Z
gpsd:DATA: NMEA0183: GPRMC time  123553.000000000 last  0.000000000 latch 1 cont 0
gpsd:PROG: NMEA0183: GPRMC starts a reporting cycle. lasttag 0
gpsd:SPIN: parse_packet() = {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|DRIVER|CLEAR|NTPTIME}
gpsd:DATA: packet type 1 from /dev/ttyS0 with {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|DRIVER|CLEAR|NTPTIME}
gpsd:DATA: all_reports(): changed {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|DRIVER|CLEAR|NTPTIME}
gpsd:SPIN: packet_get() fd 6 -> 0 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:PROG: KPPS:/dev/ttyS0 assert  1646915754.000142962, sequence: 2, clear   1646915753.100149920, sequence: 1 - using: assert
gpsd:PROG: KPPS:/dev/ttyS0 Assert cycle: 999934, duration: 899993 @  1646915754.000142962
gpsd:RAW: PPS:/dev/ttyS0 Assert pps-detect changed to 1
gpsd:PROG: PPS:/dev/ttyS0 Assert cycle: 999934, duration: 899993 @  1646915754.000142962
gpsd:PROG: PPS:/dev/ttyS0 Assert ignored missing last_fixtime
gpsd:PROG: KPPS:/dev/ttyS0 assert  1646915754.000142962, sequence: 2, clear   1646915754.100056948, sequence: 2 - using: clear
gpsd:PROG: KPPS:/dev/ttyS0 Clear cycle: 999907, duration: 99913 @  1646915754.100056948
gpsd:RAW: PPS:/dev/ttyS0 Clear pps-detect changed to 0
gpsd:PROG: PPS:/dev/ttyS0 Clear cycle: 999907, duration: 99913 @  1646915754.100056948
gpsd:PROG: PPS:/dev/ttyS0 Clear ignored missing last_fixtime
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.139262196 (Success)
gpsd:SPIN: packet_get() fd 6 -> 12 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.140017104 (Success)
gpsd:PROG: transmission pause. gap 1.004081 quiet_time 0.250000
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.140906731 (Success)
gpsd:SPIN: packet_get() fd 6 -> 10 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.141784777 (Success)
gpsd:SPIN: packet_get() fd 6 -> 10 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.142634744 (Success)
gpsd:SPIN: packet_get() fd 6 -> 10 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.143412923 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.144186955 (Success)
gpsd:SPIN: packet_get() fd 6 -> 9 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:SPIN: pselect() {3 4 6} -> { 6 } at  1646915754.144838131 (Success)
gpsd:SPIN: packet_get() fd 6 -> 3 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
gpsd:RAW: packet sniff on /dev/ttyS0 finds type 1
gpsd:RAW: raw packet of type 1, 72:$GPRMC,123554,A,46xx.xxxxx,N,7xx.xxxxx,E,000.0,000.0,100322,000.0,E*7B\x0d\x0a
gpsd:IO: <= GPS: $GPRMC,123554,A,46xx.xxxxx,N,7xx.xxxxx,E,000.0,000.0,100322,000.0,E*7B
gpsd:DATA: NMEA0183: merge_ddmmyy(100322) sets year 2022
gpsd:RAW: NMEA0183: merge_ddmmyy(100322) 2 10 122
gpsd:DATA: NMEA0183: GPRMC: registers fractional time  123554.000000000
gpsd:DATA: NMEA0183: RMC: ddmmyy=100322 hhmmss=123554 lat=46.95 lon=7.44 speed=0.00 track=0.00 mode=2 var=nan status=0
gpsd:DATA: NMEA0183: GPRMC newtime is  1646915754.000000000 = 2022-03-10T12:35:54.000Z
gpsd:DATA: NMEA0183: GPRMC time  123554.000000000 last  123553.000000000 latch 1 cont 0
gpsd:PROG: NMEA0183: GPRMC starts a reporting cycle. lasttag 61
gpsd:PROG: NMEA0183: tagged RMC as a cycle ender. 61
gpsd:PROG: NMEA0183: GPRMC ends a reporting cycle.
gpsd:SPIN: parse_packet() = {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|CLEAR|REPORT|NTPTIME}
gpsd:DATA: packet type 1 from /dev/ttyS0 with {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|CLEAR|REPORT|NTPTIME}
gpsd:DATA: all_reports(): changed {ONLINE|TIME|LATLON|SPEED|TRACK|STATUS|MODE|PACKET|CLEAR|REPORT|NTPTIME}
gpsd:SPIN: packet_get() fd 6 -> 0 (0)
gpsd:RAW: /dev/ttyS0 is known to be NMEA0183
...

Apparently, it successfully sets up the shared memory. It can also read the NMEA data, extracts date and time, and the PPS pulses are also detected! while this runs, it creates a device /dev/pps0 and with sudo ppstest /dev/pps0 I can confirm that the PPS pulses are still there. Now, in my chrony.conf, I have these two lines

refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
refclock SHM 1 offset 0.0 delay 0.1 refid PPS

so chrony should be able to read the time. However, even after a couple minutes, there is nothing:

$ chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#? NMEA                          0   4     0     -     +0ns[   +0ns] +/-    0ns
#? PPS                           0   4     0     -     +0ns[   +0ns] +/-    0ns

However I can confirm the shared memory segments are there:

$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x4e545030 0          root       600        96         2                       
0x4e545031 1          root       600        96         2                       
0x4e545032 2          root       666        96         1                       
0x4e545033 3          root       666        96         1                       
0x4e545034 4          root       666        96         1                       
...

so what is going on here? I notice that gpsd changes its own user to nobody

$ ps aux | grep gpsd
root       12667  0.0  0.0 235424  8736 pts/0    S+   13:41   0:00 sudo gpsd -D 8 -N -b -n /dev/ttyS0 /dev/pps0
nobody     12668  0.3  0.0  17172  4816 pts/0    S<l+ 13:41   0:01 gpsd -D 8 -N -b -n /dev/ttyS0 /dev/pps0

while chronyd runs as user chrony:

$ ps aux | grep chrony
chrony     12917  0.0  0.0  10600  2972 ?        S    13:45   0:00 /usr/sbin/chronyd -F 2

I believe this could be the culprit, since the shared memories belong to root. But I am not sure. Why can't get chrony the time from gpsd? I also tried the other variants, i.e. the sockets, but with the same result.

1

There are 1 answers

0
user8150417 On

As /dev/pps0 gives plausible output, these refclock lines in chrony.conf might be what you need:

refclock PPS /dev/pps0 lock NMEA refid GPS 
refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect

My system (Raspberry pi3B+ with Adafruit Ultimate GPS HAT version 2) has these non-comment lines in chrony.conf in addition to the default contents:

pool 0.europe.pool.ntp.org iburst
refclock PPS /dev/pps0 lock NMEA refid GPS 
refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect

As I understand it, the PPS system knows very accurately where the second boundaries are but it doesn't know which second the boundaries belong to. The NMEA entry is accurate enough to know which second is being timed and passes this to PPS. The 'magic' is realising that the 'noselect' entry can be assist the line that references it without itself being used directly.

Chronyc sources shows

MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS                           0   4    17    11    +18ns[ +127ns] +/-  113ns
#? NMEA                          0   4    17    13   -120ms[ -120ms] +/-  106ms
^- 169.80-203-110.customer.>     2   6    17    59   +428us[ +575us] +/-   24ms
^- 84.2.46.19                    2   6    17    59   -901us[-1185us] +/-   23ms
^- time.erickochen.nl            2   6    17    59   -141us[ -425us] +/-   12ms
^- phouchg.0x2a.io               2   6    17    59   -962us[-1245us] +/-   58ms
^- mail.rettensteiner.com        2   6    17    59   +509us[ +226us] +/-   42ms
^- ip98.mikrocom.sk              2   6    17    58  -1150us[-1433us] +/-   52ms
^- pauseq4vntp2.datamossa.io     2   6    17    58  +1777us[+1494us] +/-  177ms
^- time2.isu.net.sa              2   6    17    60    -23ms[  -23ms] +/-  413ms