Netduino PlusでNTP(SNTP)を使ってネットワーク時刻を取得するクラスを作った。また、マイコン自体のシステム時刻も同期させることができる。
こちらのサイトのおかげ。
Wrong DateTime on .NET Micro Framework Devices – Michael’s Blog
使うときはこんな感じ。
Get() でサーバーから時刻が得られる。日本用に+9時間してあるので、他のタイムゾーンでは適宜変更する。
SetLocalTime() で取得した時刻を勝手にシステム時刻に設定する。たぶん起動時にやればよい。一応定期的に同期するためのTimerやメソッドも追加した。
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | using System; using Microsoft.SPOT; using System.Net; using System.Net.Sockets; using Microsoft.SPOT.Hardware; using System.Threading; namespace Netduinist.Net { /// <summary> /// NTP サーバーから時刻を取得したり、定期的にシステム時刻を同期します。 /// </summary> public class NtpClient { /// <summary> /// NTP サーバーのホスト名もしくは IP アドレスを指定します。 /// </summary> public string Server { get; set; } private Timer syncTimer; /// <summary> /// NtpClient クラスのインスタンスを初期化します。 /// </summary> public NtpClient() { Server = "ntp.nict.jp"; } /// <summary> /// NTP サーバーから現在時刻を受信します。 /// </summary> /// public DateTime Get() { IPAddress address = Dns.GetHostEntry(this.Server).AddressList[0]; var ep = new IPEndPoint(address, 123); Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); s.Connect(ep); byte[] ntpData = new byte[48]; // RFC 2030 ntpData[0] = 0x1B; for (int i = 1; i < 48; i++) { ntpData[i] = 0; } try { s.Send(ntpData); s.Receive(ntpData); } catch { Debug.Print("Error on NtpClient.Get"); s.Close(); throw; } byte offsetTransmitTime = 40; ulong intpart = 0; ulong fractpart = 0; for (int i = 0; i { intpart = 256 * intpart + ntpData[offsetTransmitTime + i]; } for (int i = 4; i { fractpart = 256 * fractpart + ntpData[offsetTransmitTime + i]; } ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L); s.Close(); TimeSpan timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond); DateTime dateTime = new DateTime(1900, 1, 1); dateTime += timeSpan; DateTime networkDateTime = dateTime.AddHours(9); // return networkDateTime; } /// <summary> /// NTP サーバーから現在時刻を受信し、システム時刻にセットします。 /// </summary> public bool SetLocalTime() { try { var datetime = Get(); Utility.SetLocalTime(datetime); return true; } catch (Exception) { return false; } } /// <summary> /// 同期間隔 [h] を指定して、時刻同期を開始します。同期間隔は1時間~1年未満の値を時単位で指定してください。 /// </summary> public void StartSync(int syncInterval) { if (syncInterval < 1) syncInterval = 1; else if (syncInterval > 24 * 356) syncInterval = 24 * 356; syncTimer = new Timer(new TimerCallback((o) => { SetLocalTime(); }), null, 0, syncInterval * 3600); } /// <summary> /// 時刻同期を停止します。 /// </summary> public void StopSync() { if (syncTimer != null) { syncTimer.Dispose(); } } ~NtpClient() { StopSync(); } } } |