1995年製GPSタイムサーバーを「Telstra化」されないように再構築する
Rebuilding a 1995 GPS Time Server so I don't get Telstra'd (jeffgeerling.com)
要約
筆者は、1995年製のTrueTime XL-AK GPSタイムサーバーをRaspberry Pi 5とGNSS HATを使用して、Stratum 1 NTPタイムサーバーとして再構築しました。このプロジェクトでは、Raspberry Piのハードウェア設定、Chronyによる時刻同期、LCDディスプレイやLEDの活用、そしてPPS割り込みの最適化など、高精度な時刻同期を実現するための詳細な手順が解説されています。最終的な目標は、このサーバーをNTP Poolに追加することです。
全文翻訳
1995年製GPSタイムサーバーを再構築し、Telstraにサービス停止されないようにする
6月にこのTrueTime XL-AKタイムサーバーを購入し、GPSベースの時間の歴史についてもっと学びたいと思いました。
6月22日に受け取りましたが、わずか16日後に同様のGPSタイムサーバーがオーストラリアのセルサービスを12時間停止させるという出来事がありました!それについて短い動画を作成しましたが、TrueTimeの調査は後回しにしていました…が、今です。
[画像: Densitron LCDを動作させるPiを搭載したTrueTime XL-AK]
過去数週間で、このデバイスをRaspberry Piで「レストモッド」し、Stratum 1 NTPタイムサーバーを構築しました。最終的にはNTP Poolに追加したいと考えています。Pi 5とGNSS HATを組み込み、内蔵の16x2 LCDに時刻とGPSステータスを表示し、バイカラーLEDにステータスを表示し、このボックスを再び使えるようにする方法を見つけました。
ハードウェアの詳細については、今日のYouTube動画でさらに詳しく説明しています。
しかし、この記事では、Raspberry PiをStratum 1 NTPタイムサーバーとして機能させるための設定方法を説明します。
- Jimmy PaputtoのL1 GNSS HAT
- Chrony(時刻同期およびNTPサービス用)
- TimeおよびDaytimeプロトコル
- TrueTime XL-AKに組み込まれたDensitron LCD
- TrueTime AL-AKに組み込まれたバイカラーLED
- 私のTrueTime Piマウンティングブラケット
Raspberry Pi 5(4GB RAM搭載)を使用しましたが、このプロジェクトには44ドルのPi 5(1GB RAM搭載)でも問題なく使用できます(小規模ネットワーク向けのタイミングサービスのみを実行する場合)。
このサーバーの当面の必要性は、来週末のVCF Midwestに時刻サービスを提供することです。私のすべてのプロジェクトと同様に、部品は数ヶ月前から集めており、組み立ては通常、締め切り日の1〜2週間前まで待つことになります :)
Jimmy Paputto L1 GNSS HAT
[画像: Jimmy Paputto L1 GNSS HATがハンドヘルドオシロスコープで1 PPS信号を出力している様子]
付属のGPIOライザーと取り付けネジを使用して、GNSS HATをPiの上にマウントしました。下部にはネジを使用してRaspberry Piバンパーを固定しました。
Pi OS 'Lite'(GUIなし)をmicroSDカードにフラッシュした後、Jimmy Paputto GNSS HATソフトウェアをソースからビルドしました。
sudo apt -y install build-essential cmake libgpiod-dev python3-dev
git clone https://github.com/jimmypaputto/gnsshat.git
cd gnsshat
mkdir -p build && cd build
cmake .. -DBUILD_PYTHON=ON -DBUILD_EXAMPLES=ON
make -j$(nproc)
sudo make install
このソフトウェアには、NMEAセンテンス(時刻と日付の情報)をgpsdおよびchronyに転送するGNSSデータブリッジが含まれています。GNSS HATのUSB-CポートをPiのUSB-Aポートに接続して、u-blox NEO-M9Nに直接アクセスすることもできます。
インストール完了後、Raspberry Piタイムサーバー(PPS付き)の設定ガイドに従いました。
Chrony
Chronyの設定時には、/etc/chrony/chrony.conf内で以下の設定を使用しました。
# GNSS + PPS time server
# GPS time via shared memory from gpsd
refclock SHM 0 offset 0.0 delay 0.05 refid NMEA noselect
# PPS — precise edge timing
refclock PPS /dev/pps0 refid PPS lock NMEA prefer trust poll 3 filter 16
# The Pi's XO is fairly stable, but not quite TCXO-level.
maxclockerror 0.5
# Hardware timestamping for more precision on Pi 5
hwtimestamp *
# Fallback internet pools
pool 0.pool.ntp.org iburst
pool 1.pool.ntp.org iburst
# Allow all LAN clients
allow 10.0.0.0/16
# Allow requests routed through Twingate container.
allow 172.17.0.0/16
maxupdateskew 100.0
makestep 1000 3
rtcsync
# Ignore clock updates >100ms (fixes gpsd reporting time 1s off every ~31 min)
maxchange 0.1 1 -1
私はTwingateを介してリモートでNTPデモセットアップにアクセスしています。テスト中に複数のWANを扱っており、プロキシサービスで二重NATなどを通過するのが容易でした。
設定を更新した後、chronyを再起動します。
sudo systemctl restart chrony
以下のコマンドで、すべてが機能しているか確認します。
chronyc sources -v
chronyc tracking
数日間chronyのメトリクスを測定した後、私のセットアップに合わせて設定の一部を調整しました。maxclockerrorは、Piの設定をいくつか調整して発振器の周波数を安定させることができたため、デフォルトから減らしました。
Piの時刻管理の微調整
特に役立った変更点は以下の通りです。
- ファンのデューティサイクルを一定に保つ
force_turboでPiのSoCをフルスピードで動作させる- CPUコア4を分離した後、カーネルPPS割り込みをCPUコア4に割り当てる
- Piの底面を断熱し、発振器がより安定した熱環境になるようにする
- TrueTimeエンクロージャー内にPiを収め、残りの部分を断熱する
試した他のいくつかのことは、少なくとも6〜12時間のテスト期間では、測定可能な影響はないようでした。
この種のことに興味がある場合は、Austin's Nerdy Thingsのブログ記事を読むことを強くお勧めします。
安定したPiクロック
Piを2.4 GHzで動作させ続け、より安定した熱環境にするために(発振器はSoCの近くにあり、バースト的なCPUアクティビティの影響を大きく受けるため)、force_turboオプションを設定できます。これは連続して約1W多く電力を消費しますが、安定した発振器周波数(タイミングにとって重要)を得たい場合には価値があります。
/boot/firmware/config.txtに以下を追加してPiを再起動します。
# Force performance governor so CPU maintains a more stable temperature.
force_turbo=1
一貫したファン速度
PiのSoC温度を安定させるために、NTPheatのようなものをテストするのにかなりの時間を費やしました。そのようなツールは、Piを断熱すれば特に効果的です。気流、特にHVACシステムからの気流は、Piの発振器を不安定にします。安定したクロックは、測定可能であるため、一貫したドリフトを好みます。
しかし、多くのテストの結果、Piの底面(物理的にクリスタルがある場所)を断熱し、Piの残りの部分を囲み、一貫したファン速度と大きなヒートシンクで動作させることが、少なくともこれまでの数回の6〜12時間のサイクルで、より安定した周波数をもたらすことがわかりました1。
もし使用したい場合は、Time Piリポジトリで使用している小さなfan-controlユーティリティをコミットしました。75%のデューティサイクルはわずかにパフォーマンスが良かったのですが、テスト中にデスクでうるさすぎて私を悩ませるレベルでした…なので50%にしました。
オンボードRTCバッテリー充電
公式のML2020 Raspberry Pi RTCバッテリーがインストールされていると仮定して、オンボードRTCのバッテリー充電回路を設定します。
- Pi 5 RTCバッテリーを適切なヘッダーに接続します。
/boot/firmware/config.txtにdtparam=rtc_bbat_vchg=3000000を追加してPiを再起動します。- (バッテリー電圧は
vcgencmd pmic_read_adc BATT_Vで読み取れます)。
RTCバッテリーはPiの時刻管理の安定性には役立ちませんが、Piを一時的にシャットダウンした場合でも、リアルタイムから1〜2秒以内の精度を保つのに役立ちます。(数ヶ月もオフにしない限り!)
単一CPUコアでのPPS割り込みの分離
PPS割り込みの処理を完全に1つのCPUコアに専念させることで役立つか試したところ、効果がありました。本格的なタイミング機器がFPGA(またはタイミング固有のネットワークカードのようなPHCを使用)で動作する理由の1つは、決定論的なPPS処理です。LinuxカーネルのPPS機能を使用する場合、最良の場合でも、割り込みが処理されるのを待つ間に数百ナノ秒の遅延が発生します!
PPSにチャンスを与えるために、単一の専用CPUコアにPPS処理を割り当てることができます。私の場合は、すべてのPPS処理をCPU3(4番目のコア)に割り当てたいと思いました。
/boot/firmware/cmdline.txtを編集し、オプションにisolcpus=3を追加します。- 再起動:
sudo reboot /usr/local/sbin/pin-pps-irq.shを作成します(chmod +xを付けます)。内容は以下の通りです。
#!/bin/sh
irq=$(awk '/pps@/ {sub(":", "", $1); print $1}' /proc/interrupts)
[ -n "$irq" ] && echo 3 > /proc/irq/$irq/smp_affinity_list
/etc/systemd/system/pin-pps-irq.serviceを作成します。内容は以下の通りです。
[Unit]
Description=Pin PPS GPIO IRQ to isolated CPU3
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/pin-pps-irq.sh
[Install]
WantedBy=multi-user.target
- サービスを開始し、起動時に有効にします:
systemctl enable --now pin-pps-irq.service。
動作を確認します。
$ watch grep pps /proc/interrupts
# 4列目が毎秒1回増加するはずです。
166: 860 0 0 34 pinctrl-rp1 5 Edge [email protected]
1〜6時間程度、chronyの統計情報を監視し、どの程度の影響があるか確認してください。私の場合は、目立ちましたが、ゲームチェンジャーとまではいきませんでした。
モニタリングと物理的な時刻表示
Piのパフォーマンスを監視するために(この時点で、搭載されているシャーシに敬意を表して「TrueTime Pi」と呼んでいました)、Claudeの協力を得てchrony-dashboardを構築しました。
[画像: TrueTime Pi Chronyモニタリングダッシュボード]
簡単なダッシュボードを作成するのは、AIツールにとって簡単な勝利です。フロントエンドのグラフライブラリを扱うのは好きではありませんでしたし、シェルコマンドからデータを解析して定期的にSQLiteデータベースに詰め込むスクリプトを作成することは、私を興奮させるものではありません。
AIにそれを任せ、プレゼンテーションやパフォーマンスのような楽しい部分に集中できます!
Web UIは一つのことですが、TrueTimeの前面にあるヴィンテージDensitron LCDのGPIOピンのマッピングにもClaudeを使い、このプロジェクトdensitron-lcdに行き着きました。
[画像: パーフォレイテッドボード上のピンのワイヤーラッピング]
この記事の冒頭の写真には、GPS信号が安定しているLCDが動作している様子が写っています。配線には、以前試したことのないテクニック、ワイヤーラッピングを使用しました。
PiとGNSS HATでは、TrueTimeシャーシ内にデュポンコネクタ用の十分な垂直クリアランスがありませんでした(そもそもそれらのコネクタは好きではありませんが!)。GPIOピンに直接ワイヤーをハンダ付けすることを検討していましたが、標準的なスクエアピンに接続するための他のロープロファイルの方法を調べているときにワイヤーラッピングについて知りました。
プロセスはポストの角の周りに溶接を形成し、ハンダよりも低い抵抗値を持つガス密な電気接続をもたらすようです!ジョイントがシカゴまでの旅に耐えれば、プロトタイピングでこのテクニックをもう少し頻繁に使用するかもしれません。
このワイヤーラップツールとこの30 AWGワイヤーラッピングワイヤーを使用しました。
TimeおよびDaytimeプロトコル
イースターエッグとして、VCF MidwestでこのTrueTime Piサーバーを使用するため、ネットワーク上でRFC 867/868のTimeおよびDaytimeサービスも提供することにしました。
設定は簡単です。
sudo apt install xinetd
sudo systemctl enable xinetd
sudo nano /etc/xinetd.d/time
-> service time tcp set disable to "no"
-> service time udp set disable to "no"
sudo nano /etc/xinetd.d/daytime
-> service daytime tcp set disable to "no"
-> service daytime udp set disable to "no"
sudo systemctl restart xinetd
以前のブログ記事では、これらの2つのNTP以前のプロトコルの歴史について詳しく説明しています。
AppleTalk / Timelordサーバー用のnetatalk
もう一つの楽しいデモは、AppleTalk経由で時刻を取得する古いMacです!これはtimelordのおかげで、netatalkの一部として簡単に実行でき、ヴィンテージMac向けのファイルサーバーとしてAppleShareサービスを実行するなどの他のサービスと並行して利用できます。
Pi OSを実行している私のPiでは、セットアップは簡単でした。まず、LinuxカーネルでAppleTalkサービスを有効にします。
# Enable AppleTalk protocol and ensure it's loaded.
sudo modprobe appletalk && lsmod | grep appletalk
# Add AppleTalk protocol to boot modules.
echo appletalk | sudo tee /etc/modules-load.d/appletalk.conf
# Create a folder for netatalk.
mkdir -p ~/netatalk/afpshare
次に、Dockerがインストールされていると仮定して、以下の内容でDocker Composeファイル(nano ~/netatalk/compose.yml)を作成します。
services:
netatalk:
image: netatalk/netatalk:latest
container_name: netatalk
restart: unless-stopped
network_mode: host
cap_add:
- NET_ADMIN
volumes:
- ./afpshare:/mnt/afpshare
- /var/run/dbus:/var/run/dbus
environment:
AFP_USER: myname
AFP_PASS: mypass
AFP_GROUP: afpusers
ATALKD_INTERFACE: eth0
INSECURE_AUTH: "1"
AFP_EXTMAP: "1"
DISABLE_TIMEMACHINE: "1"
SERVER_NAME: "TrueTime Pi"
TZ: America/Chicago
作成したnetatalkディレクトリに移動し、コンテナを起動します。
cd ~/netatalk && docker compose up -d
ネットワーク上の他のクラシックMacは、Tardis(チョーザープラグインで起動時に一度実行されます)で時刻サービスを使用したり、AppleShareでTrueTime Piサーバーに接続したりできるようになります。
docker exec [container name] nbplkupで動作を確認できます。これにより、AFPServerとTimeLordを含むサービスリストが返されるはずです。
結論
最終的に、この結果に満足しています。Piは安全にマウントされており、2つのコネクタを再接続するだけで元のTrueTimeハードウェアに簡単に戻すことができます。
[画像: GPSジャンパーが接続されたTrueTime Piマウント完了]
このビルドを再現したい場合は…ご自由にどうぞ。私はこれが気に入っているので、さらに進めるかもしれません。あと2つやりたいことがあります。
- SMT GPIOヘッダーを備えたPCBを設計し、ロープロファイルセットアップを維持しつつ、さらに簡単な交換を可能にしたい(ワイヤーラッピングは楽しいですが、やり直すのは面倒でもあります)。
- TrueTimeキーパッドを動作させ、時刻、GPS、Chrony、ネットワーク情報の表示を切り替えられるようにしたい。
- 測定すればするほど、時刻管理は時々遅くて退屈なものだと気づきます。変更を加えても、良い測定ができるようになるまで、落ち着くまで少なくとも6〜12時間待つ必要があります!そして、環境効果のため、ほとんどの測定は少なくとも24時間以上かけて行わないと意味がありません! ↩︎