How-to use a Garmin 18x with Chrony and PPS

It’s hard to untangle what is going on as multiple things are getting mashed up in my view: loading the module, attaching line discipline, making gpsd work with serial PPS.

I’ve yet to get my hands on a Debian 12 system, but if it behaves as you describe, that would be quite a deviation from what I’ve seen with various Linux distributions and versions over the years.

1 Like

So I tried Debian 12, but couldn’t get time to Chrony from gpsd, and gpsd was having problems with PPS sometimes working, most of the time not working.

Switch to Ubuntu and now I have time working, though still not 100%. SOCK for some reason doesn’t work for me, I could not get it to work no matter what I tried, so I’m using SHM with PPS. Seems to be working fine and its been almost 24 hours and no PPS drop. However on reboot, chrony fails to start from systemctl cause PPS isn’t active, since gpsd starts after chrony. Not sure how to start gpsd before chrony cause the systemctl Before=, After=, etc etc, is all a mystery to me. But at least it works, unlike with Debian.

And speaking about PPS, I had to add in the /dev/pps0 into the gpsd.conf. Gpsd should automatically add in PPS without needing to be told to do so, but nothing seems to be able to access PPS, unless I add in the /dev/pps0 setting. And even though Ubuntu is based on Debian, it’s not pure Debian and so far isn’t dropping the PPS for no reason.

Never got SOCK to work either…

Only SHM and direct PPS.

If I use SOCK it doesn’t start ticking with PPS.

I have a Garmin GPS 19x connected to a Ubuntu Server appliance, just can’t get the PPS on CTS pin. :cry:

root@ntp:/etc# chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
#- GPS                           0   4   377    19    -16ms[  -16ms] +/- 2926us
#? PPS                           0   2     0     -     +0ns[   +0ns] +/-    0ns
^- time-a-wwv.nist.gov           1  10   377   594   -660us[ -649us] +/-   30ms
^- time-b-wwv.nist.gov           1  10   377  1031   -810us[ -809us] +/-   30ms
^- time-c-b.nist.gov             1   9   377   176   -441us[ -445us] +/-   29ms
^* pfSense.[redacted].com        1   4   377     2    +28us[  +30us] +/- 1536us``


root@ntp:~# ppscheck /dev/pps0
INFO: /dev/pps0 is a symlink to /dev/ttyS0
WARNING: time_pps_create(/dev/ttyS0)) failed: Operation not supported(95)
WARRING: /dev/ttyS0 does not appear to be a KPPS device
INFO: matching /dev/pps4 opened

Src Seconds Signals

KPPS 0.000000000 assert 0
KPPS 0.000000000 clear 0
TTY 1715009243.100228345

TTY 1715009244.000724672 TIOCM_CTS
TTY 1715009244.100330021

TTY 1715009245.000482362 TIOCM_CTS
TTY 1715009245.101164007





Submitted a feature request to add support for PPS on CTS for the Linux kernel

We will see if it gains any traction.  

https://bugzilla.kernel.org/show_bug.cgi?id=218813
1 Like

Normally it’s DCD pin 1 that has the PPS signal to be found by GPSD.

https://www.lammertbies.nl/comm/info/gps-time

Why do you want to use CTS?

Pretty clear if you read the bug report, but for clarity RJ45 COM ports don’t have the DCD pin populated.

1 Like

Not sure what your accuracy requirements are, and how adventurous you are, how much time and resources you are willing to spend. DCD is relevant for kernel PPS, which gives the best accuracy. But I believe gpsd to be able to read other pins for PPS as well, just not kernel PPS.

So if you don’t have such stringent accuracy requirements that use of kernel PPS would be imperative, and you have the means and patience to experiment and try things out a bit, you could try getting user space PPS to work off the CTS pin.

@PoolMUC

I have GPS+PPS on CTS working well on my FreeBSD based pfSense firewall appliance (RJ45 COM only), so at the moment getting GPS+PPS working under Linux with GPSD and Chrony is just an experiment to see if I can get it working under Ubuntu.

I would be interested in how to make GPSD use the CTS pin, if it doesn’t require too many hacks. Is there an easy option field or something? Or am I blazing new trails?

This is what I have so far, taken mostly from @Bas above

root@ntp:/etc/default# less gpsd 

# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/ttyS0"

# Other options you want to pass to gpsd
GPSD_OPTIONS="-n -b -s 38400"

# Automatically hot add/remove USB GPS devices via gpsdctl
USBAUTO="false"
root@ntp:/etc/chrony# cat chrony.conf | grep -v "#"

confdir /etc/chrony/conf.d

pool time.nist.gov iburst maxsources 3

server 192.168.69.5 iburst minpoll 4 maxpoll 4 prefer

refclock SHM 0 refid GPS poll 4 precision 1e-3 offset 0.100 delay 0
refclock PPS /dev/pps4 lock GPS refid PPS poll 2 precision 1e-7 

It’s a while since I have used it, that is why I am a bit cautious in my wording.

Two potential places to start would be to run gpsd or gpsmon as non-root, to prevent use of KPPS and try to force fall-back to user space PPS. gpsmon has the advantage that one sees more directly whether a PPS signal is indeed available on CTS, and being picked up. With gpsd, it’s not as directly visible as in gpsmon, and gpsd is a bit more picky about user space PPS (used to be the same, but gpsd got “improved” a while back, while maintenance of gpsmon was limited at least in this respect).

Especially if starting gpsd as non-root shows promise, then the question is how to make this work automatically at startup. One way would be to fiddle with the startup process, but at least I feel that to be preferably avoided.

Another way, also applicable if starting the stock version of gpsd as non-root did not yield an indication that it would pick up user space PPS, is to build gpsd yourself, and prevent support for KPPS being included by not providing the needed dependency at build time. On my older Debian system, that would entail removing the pps-tools package/ensuring it is not installed in the first place. Or otherwise making the header file /usr/include/sys/timepps.h (or similar, not sure whether it might be in different places on different systems) unavailable. Without support for KPPS, gpsd goes for user space PPS right away.

Start the self-built version as root, to emulate the target setting, and see whether that picks up user space PPS. If it does, obviously replace the stock version of gpsd by your self-built one, potentially also related tools for compatibility (making backups of the files so you can easily revert in the future) etc. so it is automatically started upon boot-up.

Oh, and without KPPS, your PPS device will no longer appear/be usable. I.e., you need to tell chronyd to pick up the PPS (actually, combined serial and PPS time) from SHM 1 instead of the PPS device. And since SHM 1 has the combined time, the “lock” to SHM 0 shouldn’t be necessary then. (If you start gpsd as non-root, e.g., for the first test mentioned above, then the combined time would be in SHM 3.)

@PoolMUC
sounds like more hacks than I have the patience for.

gpsmon -n results in core dump

tcp://localhost:2947          JSON slave driver>
(82) {"class":"VERSION","release":"3.25","rev":"3.25","proto_major":3,"proto_minor":15}
(219) {"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyS0","driver":"NMEA0183","readonly":"
true","activated":"2024-05-06T18:23:30.154Z","flags":1,"native":0,"bps":38400,"parity":"N","stopbits":1,"c
ycle":1.00}]}
(121) {"class":"WATCH","enable":true,"json":false,"nmea":true,"raw":0,"scaled":false,"timing":false,"split
24":false,"pps":true}
Segmentation fault (core dumped)
root@ntp:/etc/chrony# 

cgps works

┌─tttttttttttttttttttttttttttttttttttttttttt┐┌─000000000000000Seen 10/Used  9──┐
│ Time         2024-05-06T18:25:31.000Z ( 0)││GNSS  S PRN  Elev  Azim   SNR Use│
│ Latitude          26.xxxxxxxx N           ││GP  6     6  53.0  10.0  43.0  Y │
│ Longitude         80.xxxxxxxx W           ││GP  9     9  14.0  93.0  25.0  Y │
│ Alt (HAE, MSL)      -3.300,     25.400  m ││GP 11    11  56.0 295.0  49.0  Y │
│ Speed              0.00              km/h ││GP 12    12  30.0 316.0  45.0  Y │
│ Track (true, var)       0.0,  -7.2    deg ││GP 14    14  15.0 154.0  23.0  Y │
│ Climb              0.00             m/min ││GP 17    17  35.0  87.0  18.0  Y │
│ Status          3D FIX (42 secs)          ││GP 19    19  52.0  58.0  31.0  Y │
│ Long Err  (XDOP, EPX)   1.00, +/-  3.8 m  ││GP 20    20  46.0 206.0  23.0  Y │
│ Lat Err   (YDOP, EPY)   0.94, +/-  3.8 m  ││GP 22    22  39.0 160.0  19.0  Y │
│ Alt Err   (VDOP, EPV)   1.40, +/-  8.5 m  ││SB125    38   0.0   0.0   0.0  N │
│ 2D Err    (HDOP, CEP)   0.90, +/- 17.1 m  ││                                 │
│ 3D Err    (PDOP, SEP)   1.60, +/- 10.2 m  ││                                 │
│ Time Err  (TDOP)        1.17              ││                                 │
│ Geo Err   (GDOP)        2.60              ││                                 │
│ Speed Err (EPS)            +/- 27.5 km/h  ││                                 │
│ Track Err (EPD)         n/a               ││                                 │
│ Time offset             0.110390416     s ││                                 │
│ Grid Square             EL96wv54          ││                                 │
│ ECEF X, VX              n/a    n/a        ││                                 │
│ ECEF Y, VY              n/a    n/a        ││                                 │
│ ECEF Z, VZ              n/a    n/a        ││         

ppscheck sees PPS on CTS

root@ntp:/etc/chrony# ppscheck /dev/pps0
INFO: /dev/pps0 is a symlink to /dev/ttyS0
WARNING: time_pps_create(/dev/ttyS0)) failed: Operation not supported(95)
WARRING: /dev/ttyS0 does not appear to be a KPPS device
INFO: matching /dev/pps4 opened

# Src   Seconds                 Signals

  KPPS  0.000000000    assert  0
  KPPS  0.000000000    clear   0
  TTY   1715019985.000972857    TIOCM_CTS
  TTY   1715019985.100702367  

  TTY   1715019986.000382731    TIOCM_CTS
  TTY   1715019986.100640714  

  TTY   1715019987.000897455    TIOCM_CTS
  TTY   1715019987.100954034  

Ok, no worries. Especially without experience in building from source (which I don’t know whether, or not, you generally feel comfortable with), this might indeed sound hackish.

Try running with the -a option in addition. Sometimes, it’s simply the screen printing that has issues (gpsmon has been kind of deprecated, or not, for a while), but might obviously be something else as well.

Oh, I just realize I wasn’t clear: For the test with gpsmon, stop gpsd, and run gpsmon directly against the serial device: gpsmon -n -a /dev/ttyS0

E.g., with a u-blox device and user space PPS:

pi@RPi-173:~ $ gpsmon -a /dev/ttyUSB1 
gpsmon: RPi-173:/dev/ttyUSB1 9600 8N1
(10) b562050102000624325b
(12) b5620161040038692d093d45
------------------------------------- PPS -------------------------------------
(10) b5620501020006000e37

Yes, you shared previously, so sorry again for not being clear: The point was to see whether gpsmon/gpsd are also able to see the signal.

@PoolMUC

I get permission error trying to run gpsmon -a in user space

ntp@ntp:~$ gpsmon -a /dev/ttyS0
gpsmon:ERROR: SER: device open of /dev/ttyS0 failed: Permission denied(13) - retrying read-only
gpsmon:ERROR: SER: read-only device open of /dev/ttyS0 failed: Permission denied(13)

running gpsmon -a as root it does not appear to see the PPS signal (message 10 or 12)

gpsmon: ntp:/dev/ttyS0 38400 8N1
(68) $GPGGA,210529,XXXX.5953,N,XXXX.2658,W,1,08,0.9,9.9,M,-28.7,M,,*72
(74) $GPRMC,210529,A,XXXX.5953,N,XXXX.2658,W,000.1,000.0,060524,007.2,W,A*19
(55) $GPGSA,A,3,25,11,05,20,13,12,29,06,,,,,2.0,0.9,1.8*3C
(70) $GPGSV,3,1,09,51,46,228,00,25,29,260,39,11,43,052,31,05,70,305,50*7D
(70) $GPGSV,3,2,09,20,56,017,41,13,37,149,23,12,32,226,29,29,30,322,46*7E
(31) $GPGSV,3,3,09,06,15,082,23*49
(29) $PGRME,2.5,M,3.7,M,4.5,M*2C
(68) $GPGGA,210530,XXXX.5953,N,XXXX.2658,W,1,08,0.9,9.9,M,-28.7,M,,*7A
(74) $GPRMC,210530,A,XXXX.5953,N,XXXX.2658,W,000.0,000.0,060524,007.2,W,A*10
(55) $GPGSA,A,3,25,11,05,20,13,12,29,06,,,,,2.0,0.9,1.8*3C
(70) $GPGSV,3,1,09,51,46,228,00,25,29,260,39,11,43,052,31,05,70,305,50*7D
(70) $GPGSV,3,2,09,20,56,017,41,13,37,149,23,12,32,226,28,29,30,322,46*7F
(31) $GPGSV,3,3,09,06,15,082,22*48
(29) $PGRME,2.5,M,3.7,M,4.5,M*2C
(68) $GPGGA,210531,XXXX.5952,N,XXXX.2658,W,1,08,0.9,9.9,M,-28.7,M,,*7A
(74) $GPRMC,210531,A,XXXX.5952,N,XXXX.2658,W,000.0,000.0,060524,007.2,W,A*10
(55) $GPGSA,A,3,25,11,05,20,13,12,29,06,,,,,2.0,0.9,1.8*3C
(70) $GPGSV,3,1,09,51,46,228,00,25,29,260,39,11,43,052,31,05,70,305,49*75
(70) $GPGSV,3,2,09,20,56,017,41,13,37,149,23,12,32,226,28,29,30,322,46*7F
(31) $GPGSV,3,3,09,06,15,082,22*48
(29) $PGRME,2.5,M,3.7,M,4.5,M*2C
(68) $GPGGA,210532,XXXX.5953,N,XXXX.2657,W,1,08,0.9,9.8,M,-28.7,M,,*76
(74) $GPRMC,210532,A,XXXX.5953,N,XXXX.2657,W,000.5,147.9,060524,007.2,W,A*13
(55) $GPGSA,A,3,25,11,05,20,13,12,29,06,,,,,2.0,0.9,1.8*3C
(70) $GPGSV,3,1,09,51,46,228,00,25,29,260,39,11,43,052,31,05,70,305,49*75
(70) $GPGSV,3,2,09,20,56,017,41,13,37,149,22,12,32,226,28,29,30,322,46*7E
(31) $GPGSV,3,3,09,06,15,082,22*48
(29) $PGRME,2.5,M,3.7,M,4.5,M*2C
(68) $GPGGA,210533,XXXX.5952,N,XXXX.2657,W,1,08,0.9,9.8,M,-28.7,M,,*76
(74) $GPRMC,210533,A,XXXX.5952,N,XXXX.2657,W,000.0,000.0,060524,007.2,W,A*1D
(55) $GPGSA,A,3,25,11,05,20,13,12,29,06,,,,,2.0,0.9,1.8*3C
(70) $GPGSV,3,1,09,51,46,228,00,25,29,260,39,11,43,052,31,05,70,305,49*75
(70) $GPGSV,3,2,09,20,56,017,41,13,37,149,22,12,32,226,28,29,30,322,46*7E
(31) $GPGSV,3,3,09,06,15,082,21*4B
(29) $PGRME,2.5,M,3.7,M,4.5,M*2C
(68) $GPGGA,210534,XXXX.5952,N,XXXX.2657,W,1,07,1.0,9.8,M,-28.7,M,,*76
(74) $GPRMC,210534,A,XXXX.5952,N,XXXX.2657,W,000.1,000.0,060524,007.2,W,A*1B
(53) $GPGSA,A,3,25,11,05,20,13,12,29,,,,,,2.1,1.0,1.8*33
(70) $GPGSV,2,1,08,51,46,228,00,25,29,

ppstest times out

root@ntp:~# ppstest /dev/pps4
trying PPS source "/dev/pps4"
found PPS source "/dev/pps4"
ok, found 1 source(s), now start fetching data...
time_pps_fetch() error -1 (Connection timed out)
time_pps_fetch() error -1 (Connection timed out)

@PoolMUC

Here are the kernel patches that someone had to make in order to use the CTS pin for PPS

A lot more than I am willing to undertake.

Yeah, building the kernel from sources is a bit of a different animal than building a single program like gpsd.

There’s two parts to the patches:

  • Make PPS work on CTS
  • Make it configurable which pin is used

The first is relatively easy, just replicates the code responsible for the PPS from the DCD path to the CTS path as well. The main challenge here is that that is part of each device’s driver, so will have to be replicated many times over to make it more generally available. Or start with the most common driver, which seems to be what the patch does, and one has already covered most cases.

The second is a bit more elaborate, but no magic, either. And tying this into the drivers so they use it and follow the configuration.

Ah, ok. Either open up the permissions on the file for group and world (sudo chmod go+wr /dev/ttyS0) at least temporarily (run ls -lF /dev/ttyS0 first to take note of the original permissions). Or add the user to the group that the device belongs to.

Please note that I obviously don’t know what your level of expertise and familiarity with different aspects are. So I describe based on what I’d think might be helpful, things I think may be easier first, but I might obviously be completely off with my guessing.

In this case, the stuff with the non-root user are some preliminary tests to get a feel for whether attempting to get into the more involved self-building of gpsd has a sufficiently high likelihood of success. But in the end, building gpsd yourself is likely needed anyway, so if too much effort/trouble fiddling with permissions etc., skipping the preliminaries in favor of focusing on building gpsd would be a viable option as well. (By now, I think it is likely that user space PPS should work, but we obviously won’t know for sure until it’s been tried.)

@PoolMUC

Added user to dialout group. gpsmon runs. I don’t see message 10 or 12, but there is a new message TOFF

ntp@ntp:~$ gpsmon -a -n
gpsmon: tcp://localhost:2947
(82) {"class":"VERSION","release":"3.25","rev":"3.25","proto_major":3,"proto_minor":15}
(329) {"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyS0","driver":"NMEA0183","readonly":"true","activated":"2024-05-07T09:01:58.182Z","flags":1,"native":0,"bps":38400,"parity":"N","stopbits":1,"cycle":1.00},{"class":"DEVICE","path":"/dev/pps4","driver":"PPS","readonly":"true","activated":"2024-05-06T23:52:06.177Z"}]}
(121) {"class":"WATCH","enable":true,"json":false,"nmea":true,"raw":0,"scaled":false,"timing":false,"split24":false,"pps":true}
TOFF= 1715072519.060177532 real= 1715072519.000000000
(69) $GPGGA,090159,XXXX.6036,N,XXXX.2642,W,1,07,1.0,22.2,M,-28.7,M,,*4C
(74) $GPRMC,090159,A,XXXX.6036,N,XXXX.2642,W,000.0,000.0,070524,007.2,W,A*12
(53) $GPGSA,A,3,08,31,09,16,04,26,27,,,,,,2.1,1.0,1.8*38
(70) $GPGSV,2,1,08,51,46,228,00,08,27,182,19,31,33,067,25,09,19,320,33*76
(70) $GPGSV,2,2,08,16,73,000,39,04,60,322,48,26,38,037,38,27,48,144,29*76
(29) $PGRME,3.6,M,6.0,M,7.0,M*2A
TOFF= 1715072520.071685914 real= 1715072520.000000000
(69) $GPGGA,090200,XXXX.6036,N,XXXX.2642,W,1,07,1.0,22.2,M,-28.7,M,,*43
(74) $GPRMC,090200,A,XXXX.6036,N,XXXX.2642,W,000.1,000.0,070524,007.2,W,A*1C
(53) $GPGSA,A,3,08,31,09,16,04,26,27,,,,,,2.1,1.0,1.8*38
(70) $GPGSV,2,1,08,51,46,228,00,08,27,182,19,31,33,067,25,09,19,320,33*76
(70) $GPGSV,2,2,08,16,73,000,39,04,60,322,48,26,38,037,38,27,48,144,29*76
(29) $PGRME,3.6,M,6.0,M,7.0,M*2A
TOFF= 1715072521.073783073 real= 1715072521.000000000
(69) $GPGGA,090201,XXXX.6036,N,XXXX.2642,W,1,07,1.0,22.2,M,-28.7,M,,*42
(74) $GPRMC,090201,A,XXXX.6036,N,XXXX.2642,W,000.0,000.0,070524,007.2,W,A*1C
(53) $GPGSA,A,3,08,31,09,16,04,26,27,,,,,,2.1,1.0,1.8*38
(70) $GPGSV,2,1,08,51,46,228,00,08,27,182,19,31,33,067,26,09,19,320,33*75
(70) $GPGSV,2,2,08,16,73,000,39,04,60,322,48,26,38,037,38,27,48,144,29*76
(29) $PGRME,3.6,M,6.0,M,7.0,M*2A
TOFF= 1715072522.080766755 real= 1715072522.000000000
(69) $GPGGA,090202,XXXX.6036,N,XXXX.2642,W,1,07,1.0,22.2,M,-28.7,M,,*41
(74) $GPRMC,090202,A,XXXX.6036,N,XXXX.2642,W,000.1,000.0,070524,007.2,W,A*1E
(53) $GPGSA,A,3,08,31,09,16,04,26,27,,,,,,2.1,1.0,1.8*38
(70) $GPGSV,2,1,08,51,46,228,00,08,27,182,19,31,33,067,26,09,19,320,33*75

Ok, good. Remember that the point of that is to run gpsmon directly against the device as non-root (after stopping gpsd), as you did in the earlier attempt that gave the permission denied error.

Or start gpsd as non-root, then run gpsmon against gpsd (i.e., as you did with in your most recent output, looks like gpsd was started the “normal” way, i.e., likely not as non-root).

Am away from the main keyboard. But I think TOFF is for the difference/offset between serial output and system time.

As background why we fiddle with the non-root user, and why running as root does not show PPS: When gpsd sees that the mere capability of KPPS is there, it will try to use that, regardless of whether there actually is a PPS signal there or not (and in your case, there isn’t, so you don’t see gpsmon reporting it). When running as non-root, gpsd cannot access the KPPS capabilty, and only then will it fall back to user-space PPS. Which is what we want to force.

Ultimately, rebuilding gpsd without that header file mentioned prevents gpsd from having the capabilty to use KPPS at all, so it will always go straight for user-space PPS, which is what we want.

So get an USB/PCIe RS232 port and rewire the DCD wire to use it.

To give you an impression so you can decide whether, and if so, how to proceed, here the steps for building gpsd from sources (in this example from currently latest development version from GitLab). Note that one needs scons, a build tool like make, and obviously a compiler. The build is about gpsd only, i.e., many other libraries and tools are not needed, which would otherwise be needed for the various clients and the documentation etc. Maybe one needs additional tools that I happen to have installed already. The build will abort in that case and kind of hint at what is missing and needs to be installed before re-running scons.

git clone https://gitlab.com/gpsd/gpsd
cd gpsd
sudo mv /usr/include/sys/timepps.h /usr/include/sys/timepps.h.bak # gives an error if the file does not exist
scons
sudo systemctl stop gpsd
sudo mv /usr/sbin/gpsd /usr/sbin/gpsd.original
sudo cp gpsd-3.25.1~dev/gpsd/gpsd /usr/sbin
sudo systemctl start gpsd

Running gpsmon against that gpsd instance should now show that it is reading the PPS signal. Might take a few seconds until gpsd detects the PPS signal.

@PoolMUC

had some packages to install, but seems to be detecting PPS on CTS now

root@ntp:~/gpsd# gpsmon -n -a
gpsmon: tcp://localhost:2947
(111) {"class":"VERSION","release":"3.25.1~dev","rev":"release-3.25-550-g366312188","proto_major":3,"proto_minor":15}
(219) {"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyS0","driver":"NMEA0183","readonly":"true","activated":"2024-05-09T21:42:28.145Z","flags":1,"native":0,"bps":38400,"parity":"N","stopbits":1,"cycle":1.00}]}
(121) {"class":"WATCH","enable":true,"json":false,"nmea":true,"raw":0,"scaled":false,"timing":false,"split24":false,"pps":true}
TOFF= 1715290949.064670782 real= 1715290949.000000000
(69) $GPGGA,x,N,08007.2630,W,1,08,1.0,19.5,M,-28.7,M,,*43
(74) $GPRMC,214229,A,x,N,08007.2630,W,000.4,301.0,090524,007.2,W,A*15
(55) $GPGSA,A,3,11,25,20,18,29,12,05,13,,,,,1.9,1.0,1.7*3E
PPS= 1715290949.10054445 clock= 1715290950.00000000 offset=-0.899455542
------------------- PPS offset: -0.899455542 ------
(70) $GPGSV,3,1,09,51,46,228,00,11,34,079,16,25,18,238,24,20,39,036,40*7A
(70) $GPGSV,3,2,09,18,09,302,35,29,51,314,50,12,16,209,23,05,60,359,44*78
(31) $GPGSV,3,3,09,13,55,124,25*42
(29) $PGRME,3.0,M,4.7,M,5.5,M*2E
TOFF= 1715290950.074876390 real= 1715290950.000000000
(69) $GPGGA,x,N,08007.2630,W,1,08,1.0,19.5,M,-28.7,M,,*4B
(74) $GPRMC,214230,A,x,N,08007.2630,W,000.1,000.0,090524,007.2,W,A*1A
PPS= 1715290950.10022055 clock= 1715290951.00000000 offset=-0.899779446
------------------- PPS offset: -0.899779446 ------
(55) $GPGSA,A,3,11,25,20,18,29,12,05,13,,,,,1.9,1.0,1.7*3E
(70) $GPGSV,3,1,09,51,46,228,00,11,34,079,16,25,18,238,24,20,39,036,40*7A
(70) $GPGSV,3,2,09,18,09,302,35,29,51,314,50,12,16,209,23,05,60,359,44*78
(31) $GPGSV,3,3,09,13,56,123,25*46
(29) $PGRME,3.0,M,4.6,M,5.5,M*2F

now just have to figure out why there is such a huge offset

root@ntp:~/gpsd# ntpq -pn
     remote                                 refid      st t when poll reach   delay   offset   jitter
=====================================================================================================
 time.nist.gov                         .POOL.          16 p    -  256    0   0.0000   0.0000   0.0002
*192.168.69.5                          .GPS.            1 u    6    8  377   0.2640   0.0981   0.3110
+SHM(0)                                .GPS.            0 l    5    8  377   0.0000  -9.0986   7.4279
xSHM(1)                                .PPS.            0 l    4    8  377   0.0000 899.7188   0.3024
+128.138.141.172                       .NIST.           1 u   59   64    3  62.3195   6.9996   1.1998
 2610:20:6f97:97::4                    .INIT.          16 u    -   64    0   0.0000   0.0000   0.0002

I fortgot I have to manually copy /etc/ntpsec/ntp.conf to /run/ntpsec/ntp.conf.dhcp. I have a NTP server listed on my DHCP server.

# SHM PPS Setup
server 127.127.28.1 minpoll 3 maxpoll 3
fudge 127.127.28.1 time1 -0.899 stratum 0 refid PPS

root@ntp:/etc# ntpq -pn
     remote                                 refid      st t when poll reach   delay   offset   jitter
=====================================================================================================
 time.nist.gov                         .POOL.          16 p    -  256    0   0.0000   0.0000   0.0002
*192.168.69.5                          .GPS.            1 u    6    8  377   0.3776   0.0157   0.1600
-SHM(0)                                .GPS.            0 l    5    8  377   0.0000  -0.4032   7.1331
+SHM(1)                                .PPS.            0 l    4    8  377   0.0000   0.3988   0.2791
+132.163.97.6                          .NIST.           1 u   57   64    7  54.5403   1.1503   0.1110
 2610:20:6f15:15::26                   .INIT.          16 u    -   64    0   0.0000   0.0000   0.0002

I get strange results in the offset number in GPSMON. sometimes it’s -0.899, other times is near 0

TOFF= 1715292517.092666687 real= 1715292517.000000000
PPS= 1715292517.10033601 clock= 1715292518.00000000 offset=-0.899663982
TOFF= 1715292518.099786842 real= 1715292518.000000000
PPS= 1715292518.10036364 clock= 1715292519.00000000 offset=-0.899636360
TOFF= 1715292519.105796628 real= 1715292519.000000000
PPS= 1715292520.00049430 clock= 1715292520.00000000 offset= 0.000494303
TOFF= 1715292520.061630106 real= 1715292520.000000000
PPS= 1715292520.10099121 clock= 1715292521.00000000 offset=-0.899008786
TOFF= 1715292521.066162629 real= 1715292521.000000000
PPS= 1715292521.10014443 clock= 1715292522.00000000 offset=-0.899855565
TOFF= 1715292522.074831904 real= 1715292522.000000000
PPS= 1715292522.10069250 clock= 1715292523.00000000 offset=-0.899307495
TOFF= 1715292523.082004822 real= 1715292523.000000000
PPS= 1715292523.10031456 clock= 1715292524.00000000 offset=-0.899685433
TOFF= 1715292524.085917497 real= 1715292524.000000000
PPS= 1715292524.10062651 clock= 1715292525.00000000 offset=-0.899373482
TOFF= 1715292525.091519102 real= 1715292525.000000000
PPS= 1715292525.10026751 clock= 1715292526.00000000 offset=-0.899732481
------------------- PPS offset: -0.899663982 ------
------------------- PPS offset: -0.899636360 ------
------------------- PPS offset:  0.000494303 ------
------------------- PPS offset: -0.899008786 ------
------------------- PPS offset: -0.899855565 ------
------------------- PPS offset: -0.899307495 ------
------------------- PPS offset: -0.899685433 ------
------------------- PPS offset: -0.899373482 ------