Tick. Tock. Tick. Tock.§
Time is important. Debugging between machines will become a pain if the timestamps are incorrect.
If you do not have a good serial port, a USB FTDI adapter will do as well. Not sure if there is a big difference between different USB serial chips or vendors. YMMV.
Step 1: Prepare the Hardware§
You need a serial port (preferrably not USB) of your machine wired to a Meinberg module with a straight cable. The module itself probably needs its antenna attached and pointing to Mainflingen.
Well, unless you are there on vacation, then you just need to hold the module at the right angle. Tested that for you! ;)
Step 2: Temporary Timedelta§
While the Meinberg Standard Time String is, well, standard on all Meinberg clocks, it is not always on the same serial setup.
In my case, my COM52HS outputs a 9600 Baud, 7-databit, 2 stop-bit signal with even parity.
# dmesg | grep ucom ucom0 at uftdi0 portno 1 # ldattach -7e2s 9600 msts cuaU0 # attach the line discipline # sysctl hw.sensors.msts0 # check hw.sensors node for first msts sensor hw.sensors.msts0.percent0=100.00% (Signal), OK hw.sensors.msts0.timedelta0=0.005555 secs (MSTS), OK, Mon Aug 2 00:38:11.004
I attached the line discipline with ldattach(8) on
cuaU0, which is the call out device of
which is provided by
ucom0 attached to the
uftdi0 driver. Phew.
hw.sensors framework has
timedelta sensors, which is what you are seeing here.
timedelta0 shows that the last received msts(4) string contained a timestamp
which was ahead of the local clock by 5.555 milliseconds.
In an unsyncronized state, the offset might be a lot more than that.
Step 3: Make it persistent§
Since we now know that it works, it's time to make it permanent.
# tail -n 5 /etc/ttys ttyTZ none network # Clocks ttyU0 "/sbin/ldattach -7e2s 9600 msts" unknown on softcar
Reboot and the
msts(4) sensor should still exist. Yay!
Step 4: NTP§
Now that we have a persistent timedelta sensor, it's time to configure ntpd(8),
better known as
# cat /etc/ntpd.conf # To get a baseline correct time, configure a few NTP server. #server ptbtime1.ptb.de # Stratum 1, PTB also provides the source for the DCF77 senders in Germany. #server rustime01.rus.uni-stuttgart.de # Stratum 1 hosted by the uni stuttgart. server 10.20.0.1 # Internal, synced to the above and more. server time.cloudflare.com # Cloudflare's time service. Pretty good latency, stratum 3. I use this as fallback. # We want to attach msts0 with the standard refid DCF, correct it with a known 1ms delay. # Given a weight of 2, this has higher priority than a single other clock. (which have weight 1) sensor msts0 refid DCF correction 1000 weight 2 # To get more safety that we are indeed not too far from the truth, # configure some constraints that certain services should always work. # *sigh* constraint from "184.108.40.206" # quad9 v4 without DNS constraint from "2620:fe::fe" # quad9 v6 without DNS constraints from "www.google.com" # intentionally not 220.127.116.11 # Now that we are certain we have decent time, lets share it. listen on * # Bind to all interfaces. Make sure you want this. # rcctl enable ntpd # rcctl start ntpd ntpd(ok) # # wait some time
Step 5: Profit§
Now that you have waited a while, it's time to check the results.
# ntpctl -s all 2/2 peers valid, 1/1 sensors valid, constraint offset -1s, clock synced, stratum 1 peer wt tl st next poll offset delay jitter 18.104.22.168 time.cloudflare.com 1 10 3 110s 766s 8.585ms 11.372ms 2.557ms 10.20.0.1 1 10 2 383s 772s 13.309ms 5.773ms 8.913ms sensor wt gd st next poll offset correction msts0 DCF * 2 1 0 8s 15s -1.485ms 1.000ms
Even though the clock is attached via a shoddy USB serial cable, ntpd(8) seems to like it more than NTP servers. Yay! With a real PCI/PCIe serial port, the offset should be smaller as there is a lot less jitter.
Whew. Now you just need to point any NTP client to your box and.. TADA!
There are a couple of ways to improve this setup.
Using a hardware serial port will result in better timekeeping, as mentioned above. Curiosity will probably get the best of me and I'll build a latency testing setup. Or maybe I'll just graph drift with multiple devices attached to the same clock.
Adding another time source. Whether it is another Meinberg clock or a nmea(4)-compatible GNSS receiver, you will get a lot more reliable time source if you have more than one.
chrony lets you compensate local oscillator drift by using a temperature sensor. It also has some improvements in the NTP protocol which improves accuracy. Cloudflare runs it, seems to work well for them.
I wish someone would port it to OpenBSD and integrate the sensor framework. Maybe I will. Or I'll attempt to make ntpd(8) do some of those tricks. I've also been wondering if I can make this janky setup more reliable using software.
Seemingly all timedelta sensors update once every second, ntpd(8) polls every 15 seconds. Maybe if I change it to poll every second and average more values, I'll get a less jumpy clock offset.