Systemd configuring /dev/gps0 for ntpd

Hi,

I am using BBB with a GPS to get system time into NTP using the NMEA string. I’ve done this a few times before.
I have no network connection for ntpd. (It works if I have a network connection but NOT with /dev/gps0 as the only time server)

The problem:
I map /dev/ttyO1 to /dev/gps0 as a rule in /etc/udev/rules.d

systemd boots as usual and when ntpdate.service executes /dev/gps0 still isn’t ready so NTPd fails and hangs since it can’t find a time server.
I end up manually having to kill ntpd and restart the ntpdate service again

I have managed to force it to work by disabling ntpdate.service and ntpd.service in systemd and instead use CRON to call ntpd 30 seconds after boot with a ‘sleep 30’. A rubbish solution I know!
But it does highlight the fact that NTPd should not run before /dev/gps0 exists if NTP is to work properly.

My questions -

  1. How do I get ntpdate.service to only run when /dev/gps0 already exists? i.e. wait until /dev/gps0 is streaming NMEA data.

I have tried a number of ‘Before’ and ‘After’ commands in /lib/system/systemd/ntpdate.service with no apparent change.

  1. Why is the creation of /dev/gps0 taking so long? udev seems to be configuring this rule very slowly. It’s only a serial port mapping so why take 10’s of seconds?

Any help greatly appreciated!
Neil

Hi,

I am using BBB with a GPS to get system time into NTP using the NMEA string. I’ve done this a few times before.
I have no network connection for ntpd. (It works if I have a network connection but NOT with /dev/gps0 as the only time server)

The problem:
I map /dev/ttyO1 to /dev/gps0 as a rule in /etc/udev/rules.d

systemd boots as usual and when ntpdate.service executes /dev/gps0 still isn’t ready so NTPd fails and hangs since it can’t find a time server.
I end up manually having to kill ntpd and restart the ntpdate service again

I have managed to force it to work by disabling ntpdate.service and ntpd.service in systemd and instead use CRON to call ntpd 30 seconds after boot with a ‘sleep 30’. A rubbish solution I know!
But it does highlight the fact that NTPd should not run before /dev/gps0 exists if NTP is to work properly.

My questions -

  1. How do I get ntpdate.service to only run when /dev/gps0 already exists? i.e. wait until /dev/gps0 is streaming NMEA data.

I have tried a number of ‘Before’ and ‘After’ commands in /lib/system/systemd/ntpdate.service with no apparent change.

  1. Why is the creation of /dev/gps0 taking so long? udev seems to be configuring this rule very slowly. It’s only a serial port mapping so why take 10’s of seconds?

Is it possible GPS has to acquire satellites before /dev/gps0 is created?

Is it possible GPS has to acquire satellites before /dev/gps0 is created?

No. The /dev/gps0 is just a plain alias to /dev/ttyO1 (or O2, etc.) NTPd can and does access the serial interface irregardless of the state of the GPS.

OK, there are several points I can bring up. The Before and After clauses in a systemd unit file only affect the ordering of unit files and not the dependency. For a dependency, you will want either wants or requires to specify a dependency. The requires clause is a hard dependency (the unit file or device must exist and must run), while the wants clause does not require the unit file or device, but will bring it in if it exists. This is my main ntpd.service file:

[Unit]
Description=Network Time Service daemon
After=init-gps.service
After=dev-gps0.device
Requires=dev-gps0.device
Wants=init-gps.service

[Service]
Type=simple
ExecStart=/usr/local/bin/ntpd -Nng
[Install]
WantedBy=multi-user.target

You can see that it has a hard dependency on dev-gps0.device. No device, and NTPd will not run.

On my device, init-gps.service is just a wrapper to a shell script that sends commands to the GPS serial port; I’m not using it at the moment, so it is just listed as a want–not a hard dependency.

The other part is in /etc/udev/rules.d/10-gps.rules and is probably similar to your rule except for one item:

SUBSYSTEM==“tty”, KERNEL==“ttyO1”, NAME=“ttyO1”, SYMLINK=“gps0”,TAG=“systemd”

The TAG specification is very important and indicates that systemd needs to know about your device.

When implemented properly, your NTPd unit file will wait on the device until the symlink is created. Then NTP will be started. I recommend not forking NTPd – the startup options I have listed, -Nng (don’t fork, highest priority, no limits on initial time skew), appear to be the most optimal. I don’t presently use ntpdate to “presync” the device.

With a standby battery on my device (powering an RTC and the GPS), I can attain a reboot cycle of less than a minute from U-boot startup until NTPd starts and acquires the GPS. I haven’t yet optimized it, but I am very happy with my results so far.

(BTW, this has nothing whatsoever to do with the GPS constellation, etc. It should be a use-case that my (our) NTP device should be able to come up from a cold start with no fix and start talking with NTPd, whereas it will wait for a fix and choose other peers while it is doing so.)

This is my finished clock, known as BB-NTPd.