MichaIng / DietPi

Lightweight justice for your single-board computer!
https://dietpi.com/
GNU General Public License v2.0
4.8k stars 494 forks source link

Add tools for easy GPS module configuration (and, ideally, setup with time servers as a timing source) #6385

Open Kreeblah opened 1 year ago

Kreeblah commented 1 year ago

Creating a feature request

Is your feature request related to a problem? Please describe:

GPS satellites include timing data in their signals, as part of how they operate. Because of the precision required to run them, the timing data is highly accurate (in the tens or hundreds of nanoseconds). It's possible to use a GPS module to provide timing data to NTP software for serving to a local network (or the Internet at large) to improve the accuracy of the clocks on the network.

Describe the solution you'd like:

I'd love for DietPi to include tooling to make this easier. I dug through a bunch of documentation and got it working on my own, but it'd be nice for it to be supported within the project.

Describe alternatives you've considered:

The alternative is to keep things as is. My solution is up and running.

Additional context

I wrote up information as to how to get this set up from a fresh DIetPi installation both for my own reference and to hopefully help out with providing info for this request. That writeup is here: https://github.com/Kreeblah/DietPiTimeServer

I should note that it's specific to my hardware configuration (a specific GPS hat being used with a Raspberry Pi 4 B). The main differences I can think of that I'd expect with other hardware would be different serial port names (for different SBCs) and possibly a different GPIO pin for PPS data. Some hats don't have RTCs, so the I2C part is hardware-dependent as well.

Regarding USB GPS receivers, they're not particularly well-suited for setting up a time server (the document I linked explains why), but if somebody just needs positioning data, they'd work just fine. For that use case, just getting them set up with GPSd using whatever the emulated serial port the USB device provides (this probably requires USBAUTO=true in the GPSd config, though I don't have a USB GPS receiver to test with) and ignoring the NTP parts should be enough to get people ready to use whatever software they need.

MichaIng commented 1 year ago

Many thanks for your request. Indeed now I understand it better: Time sync with GPS, a very precise source, is not supported as a by systemd-timesyncd but by chrony. And a PPS helps to increase precision, when synchronising the host with the GPS signal.

For SBCs (RPi in particular) there are HATs available with GPS receiver, PPS device and RTC, connected via 40 pins GPIO header. The RPi kernel ships with device tree overlays to enable them:

Since it is about time sync, not about GEO location, I'd actually see this as a feature/option for the DietPi time sync setup. I anyway wanted to merge /boot/dietpi/func/run_ntpd and the configuration options for it, which are currently scattered across dietpi-config, into a single dietpi-timesync script, which combines UI and sync. Chrony with GPS time source could then be an additional option. I'm wondering whether to enable this for RPi only at first, on all hardware directly:

Kreeblah commented 1 year ago

For the i2c-rtc vs. i2c-rtc-gpio question, I did some looking around, and it appears that the former uses a hardware-based I2C implementation for communicating with the RTC, whereas the latter uses a software-based implementation, but adds the ability to use arbitrary pins for the I2C bus, whereas the hardware-based implementation only allows for using specific pins.

PPS devices should always be enumerated by the kernel as /dev/pps[0-9], yes. I found this document on kernel.org which mentions that as the general case (not just a Raspberry Pi-specific thing).

pps-gpio seems to be supported by a number of other vendors' boards (it's included in the mainline kernel as a module that's not tied to any specific hardware), though it looks like sometimes it needs to be compiled in (not all vendors ship kernels with it), and the way to specify the GPIO pin to use for PPS seems to vary (the gpiopin option in /boot/config.txt appears to be Raspberry Pi-specific).

If somebody specifies the wrong PPS pin for their setup, it obviously won't work, though the driver will still load and create a useless PPS device. Maybe it'd be worth mentioning the pps-tools package so that folks could use ppstest to verify their PPS devices if they're having problems? That looks like the following for a working setup:

# ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1684702395.999999332, sequence: 186254 - clear  0.000000000, sequence: 0
source 0 - assert 1684702396.999996791, sequence: 186255 - clear  0.000000000, sequence: 0
source 0 - assert 1684702397.999996601, sequence: 186256 - clear  0.000000000, sequence: 0
source 0 - assert 1684702398.999996762, sequence: 186257 - clear  0.000000000, sequence: 0
source 0 - assert 1684702399.999997691, sequence: 186258 - clear  0.000000000, sequence: 0
source 0 - assert 1684702400.999996165, sequence: 186259 - clear  0.000000000, sequence: 0

And this is what it looks like if it's not working (I booted with the pps-gpio overlay set to the wrong pin):

# ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
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)

It keeps going until the user hits control-C.

MichaIng commented 1 year ago

/boot/config.txt itself is RPi-specific yes. Aside of the kernel driver, on other SBCs, a device tree overlay would need to be present to have the GPIO configured correctly, and I have never seen such. Mainline Linux does not ship any device tree overlays and PPS is surely not enabled on any GPIO OOTB. However, we can implement the existing dtb on RPi for now and tinker with overlays for other SBCs on demand. Detection and test of /dev/pps[0-9] devices however can be done generically.

Ah nice ppstest is helpful then indeed. I hope there is a way to have it fetching data just a single time and return an exit code depending on whether it succeeded or not? That way we can implement this into our script as well.

Kreeblah commented 1 year ago

Oh, sorry. https://www.kernel.org/doc/Documentation/devicetree/bindings/pps/pps-gpio.txt has it as a device tree binding for using https://github.com/torvalds/linux/blob/master/drivers/pps/clients/pps-gpio.c, rather than an overlay. I was completely spacing on the difference there between that and an overlay and forgot to specify. But, those are usable on other boards (looking around, I see people using it on ODROID boards, Rock64 boards, and so on; this has an example of somebody using it with an older kernel on a Rock64 board by either compiling a kernel or writing an overlay file).

Unfortunately, I don't know of any tools that will test a PPS device and return. All the tools I know of just keep a running loop until manually terminated. ppstest itself only takes device paths as its parameters, and doesn't change its return code for a non-working PPS device vs a working PPS device. https://github.com/redlab-i/pps-tools/blob/master/ppstest.c is pretty straightforward, and even after somebody manually terminates the loop, there doesn't seem to be any difference between a timeout (which you get if the PPS device isn't usable) and successful tests. It'll only provide an actual return code error if it's pointed at a device that doesn't exist, isn't nominally a PPS device, etc.