PC Engines APU1 - Hopf NTP Server
Requirements
PC Enginges board, with DCD line (APU = ok, ALIX = not ok)
Debian 10 installed.
Getty on ttyS0 disabled.
APU1 to Hopf 7001 system connected over serial (see wiring below).
Hopf 7245 interface card configured for NTP (see 7245 interface board documentation).
-
Documentation
Interface board 7245 DIP-switch settings.
1 = on
0 = off
SW1 SW2 SW3
12345678 12345678 12345678
11111001 11000111 11111110
Serial cable
Construct a serial cable to route PPS to DCD.
Hopf 7245 1 GND --------- 5 GND PC Engines
S1 RS232 2 TXD --------- 2 RXD APU1 board
6 RTS (PPS) --- 1 DCD
Install packages
Install required tooling.
apt install build-essential libcap-dev pps-tools
Create device symlinks and PPS device
Create new udev rules file.
cat > /etc/udev/rules.d/hopf.rules <<EOF
KERNEL=="ttyS0", SYMLINK+="refclock-0"
KERNEL=="ttyS0", RUN+="stty -F /dev/%k 9600 cs8 -cstopb -parenb"
KERNEL=="ttyS0", TAG+="systemd", ENV{SYSTEMD_WANTS}="pps.service"
KERNEL=="pps0", SYMLINK+="refclockpps-0"
EOF
Reload the udev rules or reboot to test.
ls -l /dev/refc*
lrwxrwxrwx 1 root root 5 Jan 4 14:37 /dev/refclock-0 -> ttyS0
lrwxrwxrwx 1 root root 4 Jan 4 14:37 /dev/refclockpps-0 -> pps0
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 1578145727.901770116, sequence: 1313 - clear 1578145072.692767609, sequence: 2
source 0 - assert 1578145728.000351551, sequence: 1314 - clear 1578145072.692767609, sequence: 2
source 0 - assert 1578145728.901731373, sequence: 1315 - clear 1578145072.692767609, sequence: 2
source 0 - assert 1578145729.000557999, sequence: 1316 - clear 1578145072.692767609, sequence: 2
^C
Install NTP
Disable and remove other time sync applications.
apt-get remove --purge ntp chrony
timedatectl set-ntp false
systemctl stop systemd-timesyncd
systemctl disable systemd-timesyncd
Add ntp user.
groupadd ntp
useradd -c "Network Time Protocol" -d /var/lib/ntp -g ntp -s /bin/false ntp
usermod -a -G dialout ntp
* Create directories.<code>
install -v -o ntp -g ntp -d /var/lib/ntp
install -v -o ntp -g ntp -d /var/log/ntpstats
Compile source code.
tar zxf ntp-4.2.8p13.tar.gz
cd ntp-4.2.8p13
# from Linux From Scratch
./configure CFLAGS="-O2 -g -fPIC" \
--prefix=/usr \
--bindir=/usr/sbin \
--sysconfdir=/etc \
--enable-linuxcaps \
--enable-parse-clocks \
--with-lineeditlibs=readline \
--docdir=/usr/share/doc/ntp-4.2.8p13
make
make install
Add systemd services.
cat > /etc/systemd/system/ntpd.service <<EOF
[Unit]
Description=Network Time Service
After=syslog.target ntpdate.service sntp.service
Conflicts=systemd-timesyncd.service
[Service]
Type=forking
ExecStart=/usr/local/bin/ntpd -g -u ntp:ntp
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
systemctl enable ntpd
systemctl start ntpd
cat > /etc/systemd/system/pps.server <<EOF
[Service]
Type=simple
ExecStart=/usr/bin/ppsldisc /dev/ttyS0
EOF
Hopf DCF /etc/ntp.conf
Create /etc/ntpd.conf.
#Stratum level when no ref source available
tos orphan 12
# Hopf DCF clock
# Mode 12 + 128 (pps) = 140
server 127.127.8.0 mode 140
fudge 127.127.8.0 refid PPS # Reference identifier
#leapfile /etc/leap_second
restrict -4 default notrap nomodify nopeer noquery
restrict -6 default notrap nomodify nopeer noquery
restrict 127.0.0.1
restrict ::1
statsdir /var/log/ntpstats/
statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
driftfile /var/lib/ntp/ntp.drift
Check timecode
ntpq -c 'cv 0 timecode'
timecode="\x02CB154556010120\x0a\x0d\x03"
Nagios Hopf 7001 check
#!/bin/bash
#
# Tested with Hopf 7001 DCF Base station with 7245 serial interface boards
# Datastring 7001/6021
#
# Ben Stienstra, 2013/05
ntpq="/usr/bin/ntpq"
# get timecode variable, received from the clock
eval `$ntpq -c 'cv 0 timecode'`
function quit {
case "$2" in
0) echo "OK: $1"
exit 0
;;
1) echo "Warning: $1"
exit 1
;;
2) echo "Critical: $1"
exit 2
;;
3) echo "Unknown: $1"
exit 3
;;
esac
}
function clockstat {
# Status nibble from hex
hex0=0000
hex1=0001
hex2=0010
hex3=0011
hex4=0100
hex5=0101
hex6=0110
hex7=0111
hex8=1000
hex9=1001
hexA=1010
hexB=1011
hexC=1100
hexD=1101
hexE=1110
hexF=1111
eval statnibble='hex$1'
snibble=${!statnibble}
case ${snibble:0:2} in
00)
textstatus="time/date invalid"
exitcode=2
;;
01)
textstatus="crystal operation"
exitcode=1
;;
10)
textstatus="radio operation"
exitcode=0
;;
11)
textstatus="radio operation (high accuracy)"
exitcode=0
;;
esac
case ${snibble:2:1} in
0)
dss="standard time"
;;
1)
dss="daylight saving time"
;;
esac
case ${snibble:3:1} in
0)
ann="no announcement hour"
;;
1)
ann="announcement (ds-st-ds)"
;;
esac
quit "status hex=\"$1\", bin=\"$snibble\": $textstatus, $dss, $ann" $exitcode
}
# check for complete string, for example: \x028D194223310513\x0a\x0d\x03
# This is from the Hopf 7245 serial interface board
#
# x20 = Space
# x0D = CR (carriage return)
# x0A = LF (line feed)
# x02 = STX (start of text)
# x03 = ETX (end of text)
#
if [[ $timecode == \\x02*\\x0a\\x0d\\x03 ]];
then
clockstat ${timecode:4:1}
else
quit "Timecode not complete" 3 # return Unkown status
fi
Troubleshooting
Show peer status:
ntpq -p
Show timecode from receiver:
ntpq -c 'cv 0 timecode'
Show client list (max. 600):
ntpdc -n -c monlist
## ntp 2.4.7 removed monlist in favour of ntpq's mrulist
ntpq -c "mrulist"