Distributing radio time to your local network

Ben Clifford
benc@hawaga.org.uk

Why time?

  • Compare log files on two machines
  • Is an HTTPS certificate is valid now?
  • When was a message sent?

What is wrong with clocks?

  • Clock might be offset from correct time.
    Pi doesn't know real time at startup. Buy a £6 RTC..
  • Clock might tick at wrong rate (not 1 sec/sec): manufacturing variation. anecdote: Pi loses 12 s/day (0.5s/hour)
  • Clock might vary in rate: temperature. Big Ben is adjusted with pennies 1d =0.42p = 9.45g = 0.4s/day
  • Astronomers might fiddle with time: leap seconds

Distributing Time

1833: Greenwich time ball
>=1926: UK government radio time signals such as MSF
1936: UK speaking clock
>=1979: internet-style protocols such as NTP
>=1983: GPS available for civilian use

My setup

Receives UK government MSF time; makes it available over NTP (Network Time Protocol) to my home network (and beyond).

radio receiver -> GPIO pin -> C decoder -> NTP -> ethernet

Radio signal

60kHz radio signal that pulses on and off a few times per second.
Transmitter has 3 on-site atomic clocks

Receiver in commodity clocks and something like this board

map © OpenStreetMap contributors

Protocol

Two bits per second - same protocol on carrier wave and on the wire from receiver to Pi GPIO pin

One time stamp per minute

BCD (binary coded decimal): Year (8 bits), Month (5 bits), Day (5 bits), Day of week (3 bits), Hour (6 bits), Minutes (7 bits), Timezone (1 bit), Parity (4 bits)

Seconds are implicit

Datasheet

MSF protocol decoder

I wrote this for fun. There are other implementations on the internet.

Language: C

Decodes signal into a time stamp and passes it to ntpd via a memory buffer.

https://github.com/benclifford/msf

ntpd

ntpd takes time signals from several sources, and makes your computer clock track the best source.

It also makes your clock's time available to other computers elsewhere on the network.

Commonly: point at pool.ntp.org public time servers.

In my case: in addition, look at decoded MSF signal

How well does it work?

It's OK but not amazing.

Radio signal is weak and drops out for hours at a time. NTP automatically switches to other (internet based) time sources in this case.

jitter is very high compared to internet based time sources

ntpd cannot estimate latency automatically - handle this by comparing against other (internet based) time sources and putting this in ntpd config file

End of overview

More in depth stuff now, as desired.
* memory buffer

system time at time of reading
time according to this time stamp
flag: is this buffer valid? [actually not this - correct it]

effectively recording the error between the system clock and
the time source...

* ntpd

apt-get to install this.

doesn't just blindly reset clock to what our receiver says.
Instead it can track several time servers - for example, this one
and a couple on the internet - and models the accuracy
of those clocks, and picks whichever clock is "best" (for some
definition) to slowly adjust towards (so that we don't get big
jumps in system time).

How to configure ntpd to use a buffer:
[TODO: extract from config]

look at status:

here we can see it knows about the MSF driver, but it has not
chosen to follow it - it's following the one with a *, and
the ones with + are a sort of runner up in the choosing process.
So here it has chosen to track time from my ISP's time server
- which is a stratum 2 server - meaning this ntp daemon will be
stratum 3. This is because wiring messed up and I'm not receiving
any time messages and ntpd has found a better time source.

that's because it's the wrong pi!

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
-81.2.122.172    90.155.53.94     3 u  171 1024  377    0.678    2.521   0.586
+biscay.cqx.ltd. 91.189.89.199    3 u  374 1024  377   31.517    1.844   1.364
 SHM(2)          .MSF.            0 l    -   64    0    0.000    0.000   0.000
*ntp1.aa.net.uk  195.66.241.3     2 u  505 1024  377   11.701    0.845   0.380
-dildano.hawaga. 188.39.213.7     2 u  770 1024  176   17.180    3.570   0.873
+pygar-6.hawaga. 188.39.213.7     2 u  170 1024  377   20.834    1.086   1.341

on the right pi:

npi@faeroe ~ $ ntpq -pn
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+90.155.53.94    195.66.241.3     2 u   50   64  377    6.345    0.303   1.860
*127.127.28.2    .MSF.            0 l   11   64  167    0.000   -2.587   3.437
+2001:8b0:1638:9 81.2.122.172     2 u    7   64  377    0.829   -2.677   1.756

Go over each column in this.



And on another host, which is syncronised from this:

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*81.2.122.172    .MSF.            1 u  287 1024  377    1.238    0.437   2.001
+biscay.cqx.ltd. 213.95.200.109   3 u  407 1024  377   33.681   -3.230   5.386
+ntp1.aa.net.uk  195.66.241.2     2 u  297 1024  377   23.248   -7.219   7.755
 dildano.hawaga. 188.39.213.7     2 u   5h 1024    0   15.896    1.865   0.000
 pygar.hawaga.or 188.39.213.7     2 u   6h 1024    0   23.405   -0.833   0.000

config:

a network based timeserver:

server 90.155.53.94

this MSF server:

server 127.127.28.2
fudge 127.127.28.2 refid MSF time1 0.030

127.127.28.2 is a fake IP address that
means use reference clock driver 28.2
which means use a shared memory buffer.
different values there mean to use different
drivers in NTP to get time from a reference
clock, often tied to specific clock hardware.

time1 is a manually configured time
offset - see later section.


refid is the name we will publish this time
source under: see ntpq output. By convention,
MSF is used for this particular radio time
signal.

More detail on the protocol decoder

How to build the C code

How to make it start at boot
(ntpd already does...)


C code and shell wrapper:

  how to read a GPIO pin in C - edge based (I think)
    - how to configure it from bash - see 'start.sh'
  shift buffer implementation
  parity checking
  how to write to a shared memory buffer for NTP

  anything else?

Example output:

In the first case, when it wasn't connected:

msf shift.c
main: getting NTP shm
Key:
  . = edge detected on input pin
  T = timeout without edge on input
  > = Starting decode
 X0 = Decode failed: insufficient zeroes in scan zone
 X1 = Decode failed: insufficient ones in scan zone
  * = Decode inhibition ended
main: entering main loop
..TTTTTTTTTT

But, on the right pi:
[TODO: a video of this happening, screenshot-as-gif? so that it
can be viewed offline, appear on slides?]

....................................................................................................>
                                                    

checkdecode: matched num ones threshold, numOnesInFirst = 250
checkdecode: numZeroesInSecond = 247
checkdecode: Matched num zeroes threshold
decode: Decoding
decodeBCD: Decoding
decodeBCD: Decoded time is '17/07/11 23:20 BST
tellNTP: Telling ntpd
tellNTP: ntpmem is 0x76f78000
tellNTP: ntpmem->mode = 0
tellNTP: ntp struct is free, so we can populate it.
tellNTP: MSF time           =  1499811600 seconds
tellNTP: system edge time   =  1499811600.033369 seconds
tellNTP: system report time =  1499811600.034633 seconds
tellNTP: result delivered to ntpd

about 33ms off...

now the bad stuff

* dodgy bits of hardware

This was my first raspberry pi hardware project, and my first
electronics dabbling in around 15 years.

The connectors and project housing are terrible: dodgy solder.

Probably a headphone jack would be a better connector?

Location of device is really awkward - I've only got one corner
up on a curtain rail in my flat that I can get a signal and still be
in wire-length of the pi.

At the pi end it's jumpers jammed into breadboard, because I also
use that pi for trying out new stuff.

also mention?

wired up a GPS I had sitting around to ntpd to see how easy
that was. http://benctechnicalblog.blogspot.com/2017/07/wintec-grays-2-gps-device-feeding-to-ntp.html
that has a crazy big offset!

ntpd can have multiple stratum 0 clocks: