Ben Clifford
benc@hawaga.org.uk
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
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
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
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
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.
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
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
* 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.
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...
* 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: