2022年10月7日 星期五

[小知識]從 arduino 學到 NTP packet

 NTP 是網路對時的協定,在一般因為是作業系統自動處理,所以也不知到哪裡找資訊。

反而因為 arduino 這類 MCU 興起的關係,很多老協定的原始碼與 SPEC 就有了關鍵字可以深探與學習。

重點

* UDP 傳送,48 BYTE,UTC時間

兩段重點程式

```

unsigned long sendNTPpacket(IPAddress& address) {

    Serial.println("sending NTP packet...");

    // set all bytes in the buffer to 0

    memset(packetBuffer, 0, NTP_PACKET_SIZE);  //clear the buffer

    //Initialize values needed to form NTP request

    //(see URL above for details on the packets)

    packetBuffer[0]=0b11100011;   // LI, Version, Mode

    packetBuffer[1]=0;     // Stratum, or type of clock

    packetBuffer[2]=6;     // Polling Interval

    packetBuffer[3]=0xEC;  // Peer Clock Precision

    //8 bytes of zero for Root Delay & Root Dispersion

    packetBuffer[12]=49;

    packetBuffer[13]=0x4E;

    packetBuffer[14]=49;

    packetBuffer[15]=52;

    // all NTP fields have been given values, now

    // you can send a packet requesting a timestamp:

    udp.beginPacket(address, 123); //NTP requests are to port 123

    udp.write(packetBuffer, NTP_PACKET_SIZE); //send UDP request to NTP server

    udp.endPacket();

    }

```


```

unsigned long getUnixTime() {

    WiFi.hostByName(ntpServerName, timeServerIP);  //get a random server from the pool

    sendNTPpacket(timeServerIP);                   //send an NTP packet to a time server

    delay(1000);                                   // wait to see if a reply is available


    int cb=udp.parsePacket();                      //return bytes received

    unsigned long unix_time=0;

    if (!cb) {Serial.println("no packet yet");}

    else {  //received a packet, read the data from the buffer

        Serial.print("packet received, length=");

        Serial.println(cb);                        //=48

        udp.read(packetBuffer, NTP_PACKET_SIZE);  //read the packet into the buffer


        //the timestamp starts at byte 40 of the received packet and is four bytes,

        //or two words, long. First, esxtract the two words:

        unsigned long highWord=word(packetBuffer[40], packetBuffer[41]);

        unsigned long lowWord=word(packetBuffer[42], packetBuffer[43]);

        //combine the four bytes (two words) into a long integer

        //this is NTP time (seconds since Jan 1 1900):

        unsigned long secsSince1900=highWord << 16 | lowWord;

        Serial.print("Seconds since Jan 1 1900=" );

        Serial.println(secsSince1900);

        Serial.print("Unix time=");

        //Unix time starts on Jan 1 1970. In seconds, that's 2208988800:

        unix_time=secsSince1900 - 2208988800UL;

        Serial.print(F("Unix time stamp (seconds since 1970-01-01)="));

        Serial.println(unix_time); //print Unix time

        }  

    return unix_time; //return seconds since 1970-01-01

    }

```


參考

* [Arduino C on ESP8266 學習筆記 (三) : 從 NTP 伺服器取得網路時間](http://yhhuang1966.blogspot.com/2017/09/arduino-ide-esp8266-ntp.html)

沒有留言:

張貼留言