マイコンからSNTPを利用するためのテスト

某ハードウェア版もえくろ の件。
 
ハードウェアの準備や設計は後回しで、とりあえずSNTPというプロトコルと、その時計合わせの仕組みを理解するところから。
 
まず、LAN内にNTPサーバを立て、Delphi上で書いたコードから問い合わせを行い時間情報を取得するまでをやってみる。
 

1.SNTPサーバの123ポートに対し、UDPで$23000000…(以下、44バイト分のゼロデータ)を送出
2.wktkしながらUDPで受信待ち(タイムアウトは仮で1000ms)
3.同じサイズ(48バイト)のデータが戻ってくる
 
データから時間情報を取り出す。
まず、LIに変なフラグが立ってないかとか、Modeフラグが4(Serverからの返答)かをチェック。
使えそうなデータだったら、
41バイト目から4バイト(32ビット)を取り出し、サーバが応答を送信した時刻(1900/01/01 00:00:00 からの秒数)を計算。続く45バイト目をとりだし、先頭の4ビット程度を下記の要領で計算。

ミリ秒用の変数(msdとする)を用意・初期化。
1ビットが1なら、msdに2の−1乗を加算。
2ビットが1なら、msdに2の−2乗を加算。
3ビットが1なら、msdに2の−3乗を加算。
これを必要なだけ繰り返し、最後にmsdへ1000を掛ける。
(32ビット全てを計算する必要はない。せいせい6ビット程度で十分。有効桁以降は乱数が埋め込まれているので計算するだけ無駄)

 
本来は要求を受信した時刻も計算し、サーバの応答にかかった時間を続くラグ計算に組み込むべきだが、高負荷なサーバでないプライベートなSNTPサーバであれば無視できるので、ここでは割愛。
 
次に、サーバが返答を送ってこちらに届くまでに生じるラグを計算する。
こちらがSNTPパケットを送出した時刻(ローカルのタイマ。時刻は合っていなくてもOK)から返答を受け取るまでの時刻(同様)の差を計算、それを2で割ったものをサーバが応答を返した時刻に加算する。
 
これで求められた時刻が、SNTPの応答を受信した瞬間の時刻ということになる。
 
 
 
ここで、1900/01/01 00:00:00 からの経過秒のデータをAVR上で年月日に計算する手間を考えて愕然としたが、もえくろ 時計サーバから送られるデータフォーマットを、この 1900/01/01 00:00:00 基準の計算方法に揃えておけばいい(専用のCGIを作成)。
そうすれば、年月日や閏年閏秒などの面倒な事は一切無視して、純粋な整数値で時間を計算できる。うん、この手でなんとかいけそうだ。
 
 
これでSNTP経由でいつでも正確な時間が取り出せるという理屈。
マイコン上で生成する1秒の精度には限界があるので、1時間に1回程度の時計合わせが必要になりそうだが・・・。クロックモジュールを実装してもいいが、そうなると年月日の計算がからんでくるからなぁ。内部的には日付は適当にしておいて、時刻だけ一致させて使えばいいか。
 
 
本当はイーサネットのデータ制御という、一番低レベルな処理もゴリゴリ書かなくちゃいけないんだけどね・・・。
うーむ。来月頃にEthernet付きのマイコンボードを買って(組んで?)、ぼちぼち実装テストも始めてみるかな。