Using GPS as a time source for ntpd

Remove chrony and disable systemd-timesyncd

 sudo apt purge chrony
 sudo systemctl stop systemd-timesyncd
 sudo systemctl disable systemd-timesyncd

Configure ntpd

Download the latest stable ntpd from https://www.ntp.org/downloads.html

 wget http://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-4.2.8p14.tar.gz
 tar -zxf ntp-4.2.8p14.tar.gz
 cd ntp-4.2.8p14
 sudo apt install build-essential libcap-dev
 ./configure --prefix /opt/ntp-4.2.8p14 --enable-linuxcaps
 make
 sudo make install
 sudo ln -s /opt/ntp-4.2.8p14 /opt/ntp
 
 sudo vi /etc/ntp.conf
 driftfile /var/lib/ntp/ntp.drift
 leapfile /usr/share/zoneinfo/leap-seconds.list
 pool 0.pool.ntp.org iburst
 pool 1.pool.ntp.org iburst
 pool 2.pool.ntp.org iburst
 pool 3.pool.ntp.org iburst
 server 127.127.28.0
 fudge 127.127.28.0 refid GPS
 server 127.127.28.1 prefer
 fudge 127.127.28.1 refid PPS
 restrict default kod noquery limited
 restrict <your-network> mask <your-network-mask> kod nomodify nopeer limited
 restrict 127.0.0.1 mask 255.255.255.255
 sudo vi /lib/systemd/system/ntpd.service
 [Unit]
 Description=Network Time Service
 Documentation=man:ntpd(8)
 Wants=network.target
 ConditionCapability=CAP_SYS_TIME
 After=network.target nss-lookup.target
 Conflicts=systemd-timesyncd.service
 [Service]
 Type=forking
 PrivateTmp=true
 ExecStart=/opt/ntp/bin/ntpd -g -N -u ntp:ntp
 Restart=on-failure
 [Install]
 WantedBy=multi-user.target
 sudo groupadd ntp
 sudo useradd -g ntp -s /usr/sbin/nologin ntp
 sudo systemctl enable ntpd
 sudo systemctl start ntpd

Install and configure the latest gpsd

 wget http://download.savannah.gnu.org/releases/gpsd/gpsd-3.21.tar.gz
 tar -xzf gpsd-3.21.tar.gz
 cd gpsd-3.21
 sudo apt install scons libncurses5-dev python-dev pps-tools
 scons prefix=/opt/gpsd-3.21 timeservice=yes aivdm=yes
 scons check
 sudo scons udev-install
 sudo ln -s /opt/gpsd-3.21 /opt/gpsd
 sudo vi /etc/default/gpsd.conf
 START_DAEMON="true"
 USBAUTO="true"
 DEVICES="/dev/ttyAMA0 /dev/ttyUSB0"
 GPSD_OPTIONS="-G -n -s 38400"
 sudo systemctl enable gpsd
 sudo systemctl start gpsd

Troubleshooting/Verifying

 cgps
 /opt/ntp/bin/ntpq -p
 sudo /opt/gpsd/bin/ntpshmmon
 cat /proc/sysvipc/shm
 ipcs -i 0 -m
 ipcs -i 1 -m

Raspberry Pi specific for GPS devices with time pulse signal

Assuming serial GPS, connect the time pulse line to GPIO18, connect TX and RX lines to uart0 pins (GPIO15 and GPIO14 respectively) via a level shifter, of course, if the GPS device is 5v.

 sudo vi /boot/firmware/usercfg.txt
 dtoverlay=pps-gpio,gpiopin=18
 dtoverlay=uart0
 sudo reboot
 lsmod|grep pps
 ppstest /dev/pps0
 lsof|grep pps

To correctly interprete u-blox UBX-TIM-TP messages, UBX-NAV-CLOCK is also needed. All these can be enabled with gnss tool - https://github.com/creatica-soft/Gnss/tree/master/rpi

 g++ -O -o gps gps.cpp -lreadline
 ./gps
 open com1 /dev/ttyAMA0 9600
 ubxRate tp
 ubxRate clock
 ubxRate pvt
 config save