Preface and spoiler (kinda): Need an NTP server? Try mine at ntp.ferrara.space. Stats available here.

I recently picked up an Arbiter 1093B satellite controlled clock that is purportedly accurate to less than 500ns (5.0e-7 seconds). I didn't want to just rack it and have it sit around collecting dust, as was the case in it's previous home, and started doing some research as to how I could effectively use this clock as a public NTP server.

My first course of action was to determine if there were any modifications or additions to the clock that I could purchase to easily solve this problem. Per the product page on the Arbiter website, the 1093B has option boards that can be purchased separately to provide extra functionality to the clock. Option 34 piqued my interest as that is labeled as a "Network Time Protocol (NTP) / Precision Time Protocol (PTP) Server". Neat, I think. Problem solved! Not so fast though...

I reached out to Arbiter and requested a quote for purchasing this addon board. Unfortunately, upon receiving the quote of ~$900 USD, I was a bit disappointed. There wasn't any way in hell I was shelling out that much money as a college student. And so begins the journey of creating my own IRIG-B decoder, and realizing there was a much easier solution to this problem...

I looked through the manual to determine what protocols I had available to read the data coming from the clock, and wound up looking into the available IRIG-B output. The IRIG time code standard was established in the 60's by the Inter-Range Instrumentation Group and uses pulse-width coding to communicate data. As the output is a +5v signal from the Arbiter, simply connecting the ground to the Arduino's ground pin, and the signal output from the Arbiter to an available digital pin on the Arduino is all that is needed to decode the signal (provided you have a 5v tolerant Arduino - I'm using an Arduino Uno. YMMV.).

As this was my first project with decoding digital data, I was a bit intimidated as to how much would have to be done to simply read some accurate time from the Arbiter device. After reading through a spec sheet on the IRIG timecode, I found the matter of decoding the unmodulated IRIG-B output quite simple. The IRIG-B signal results in 100 +5v pulses every second, with the first pulse being the "on-time" 1 pulse-per-second signal. Every 10 pulses, there is a REF marker that I use to determine what data is currently ready to be parsed. See this great diagram for more information.

The gist of decoding a pulse-width modulated signal goes a bit like this...
1. Look for the rising edge of the signal, record this time. I used millis() within Arduino.
2. Look for the falling edge of the signal, record this time. Determine the type of pulse via it's length ±1ms. If the pulse length is between 7 and 9 milliseconds, this is a reference (REF) marker (8ms nominal). If the pulse length is between If the pulse length is between 1 and 3ms, this is a ZERO. If the pulse is anything else, assume it's around 5ms and represents a ONE.
3. Push the pulse type into queue
4. Once we've found another REF, parse the queue and do something with the data.

At this point, I began to move my code into a library so it could be easily implemented into any Arduino project for reading IRIG-B time. (If you are interested in using this library, please note it is not complete and I can not guarantee any accuracy, nor if it will work with your make/model reference clock. YMMV.) I also discovered that using the serial port is much easier, and that the ntp software already had a driver available for my device. Combine this with a Raspberry Pi, and you've got yourself a stratum 1 NTP server.

Moral of the story: make sure you read through every link of the ntp documentation. It's a bit of a maze to find information provided you aren't familiar with the terminology.