From 1c77e1636e5c0ce9f5e7d96e1a4db866a93135a1 Mon Sep 17 00:00:00 2001 From: WhymustIhaveaname <38423345+WhymustIhaveaname@users.noreply.github.com> Date: Fri, 24 Apr 2020 08:36:06 +0100 Subject: [PATCH 1/4] change a lots --- NTPClient.cpp | 127 ++++++++++++++++++++++++++++++++++++++++---------- NTPClient.h | 33 +++++++++++-- 2 files changed, 133 insertions(+), 27 deletions(-) diff --git a/NTPClient.cpp b/NTPClient.cpp index b435855..e7ff0d6 100755 --- a/NTPClient.cpp +++ b/NTPClient.cpp @@ -82,48 +82,112 @@ void NTPClient::begin(unsigned int port) { } bool NTPClient::forceUpdate() { - #ifdef DEBUG_NTPClient - Serial.println("Update from NTP Server"); - #endif - // flush any existing packets while(this->_udp->parsePacket() != 0) this->_udp->flush(); + uint32_t tik,tok; //tik,tok to record wait time, replace timeout this->sendNTPPacket(); + tik=millis(); + #ifdef DEBUG_NTPClient + Serial.println("sent ntp packet"); + #endif // Wait till data is there or timeout... - byte timeout = 0; - int cb = 0; + uint16_t cb = 0; do { - delay ( 10 ); + delay (1); //poll more frequently to get high accuarcy cb = this->_udp->parsePacket(); - if (timeout > 100) return false; // timeout after 1000 ms - timeout++; + if ((millis()-tik)>this->_ntp_timeout){ + this->_last_fail=millis(); + return false; + } } while (cb == 0); - - this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time + tok=millis(); + #ifdef DEBUG_NTPClient + Serial.println("got ntp packet."); + Serial.print("tik, tok, (tok-tik)/2: "); + Serial.print(tik);Serial.print(", "); + Serial.print(tok);Serial.print(", "); + Serial.println((tok-tik)/2.0); + #endif this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE); - - unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]); - unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]); + uint32_t high_word,low_word; + uint32_t receive_int,transmit_int; //integer part // 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; + high_word=word(this->_packetBuffer[32],this->_packetBuffer[33]); + low_word=word(this->_packetBuffer[34],this->_packetBuffer[35]); + receive_int=(high_word<<16) | low_word; + high_word=word(this->_packetBuffer[40],this->_packetBuffer[41]); + low_word=word(this->_packetBuffer[42],this->_packetBuffer[43]); + transmit_int=(high_word<<16) | low_word; + #ifdef DEBUG_NTPClient + Serial.print("receive_int, transmit_int: "); + Serial.print(receive_int);Serial.print(", "); + Serial.println(transmit_int); + #endif + + float receive_dec=0,transmit_dec=0; //decimal part + high_word=word(this->_packetBuffer[36],this->_packetBuffer[37]); + receive_dec=high_word/65536.0; + #ifdef DEBUG_NTPClient + Serial.print("receive_dec, transmit_dec: "); + Serial.print(high_word,HEX);Serial.print(", "); + Serial.print(receive_dec,6);Serial.print(", "); + #endif + high_word=word(this->_packetBuffer[44],this->_packetBuffer[45]); + transmit_dec=high_word/65536.0; + #ifdef DEBUG_NTPClient + Serial.print(high_word,HEX);Serial.print(", "); + Serial.println(transmit_dec,6); + #endif + + float ping_delay; + ping_delay=(tok-tik)/1000.0-(transmit_int-receive_int)-(transmit_dec-receive_dec); + ping_delay/=2.0; + if(ping_delay<=0){ + Serial.println("ERROR: ping_delay < 0.0!"); + } + + this->_lastUpdate=tok; + this->_currentEpoc=transmit_int - SEVENZYYEARS ; + this->_current_epoc_dec=ping_delay+transmit_dec; + if(this->_current_epoc_dec>1){ + this->_currentEpoc+=(int)this->_current_epoc_dec; + this->_current_epoc_dec-=(int)this->_current_epoc_dec; + } - this->_currentEpoc = secsSince1900 - SEVENZYYEARS; + #ifdef DEBUG_NTPClient + Serial.print("current Epoc: "); + Serial.print(this->_currentEpoc);Serial.print(" "); + Serial.println(this->_current_epoc_dec,6); + #endif return true; // return true after successful update } -bool NTPClient::update() { - if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval - || this->_lastUpdate == 0) { // Update if there was no update yet. - if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed - return this->forceUpdate(); +int8_t NTPClient::update() { + uint32_t now=millis(); + if(now>=this->_lastUpdate){ //if not overflow + if(now-this->_lastUpdate>=this->_updateInterval){ + if(now-this->_last_fail >= 1500){ + return this->forceUpdate(); + }else{ + return 3; //return 3 if last failed was just happen + } + } + }else{ //if overflowed + if(now+0xffffffff-this->_lastUpdate >= this->_updateInterval){ + if(now+0xffffffff-this->_last_fail >= 1500){ + return this->forceUpdate(); + }else{ + return 3; + } + } } - return false; // return false if update does not occur + return 2; // return 2 if update does not occur } bool NTPClient::isTimeSet() const { @@ -133,7 +197,13 @@ bool NTPClient::isTimeSet() const { unsigned long NTPClient::getEpochTime() const { return this->_timeOffset + // User offset this->_currentEpoc + // Epoch returned by the NTP server - ((millis() - this->_lastUpdate) / 1000); // Time since last update + ((millis() - this->_lastUpdate + (int)(this->_current_epoc_dec*1000)) / 1000); // Time since last update +} + +float NTPClient::get_millis() const{ + float ms = millis() - this->_lastUpdate + this->_current_epoc_dec*1000.0; + ms-=(int)(ms/1000)*1000; + return ms; } int NTPClient::getDay() const { @@ -178,7 +248,16 @@ void NTPClient::setUpdateInterval(unsigned long updateInterval) { } void NTPClient::setPoolServerName(const char* poolServerName) { - this->_poolServerName = poolServerName; + this->_poolServerName = poolServerName; +} + +void NTPClient::setPoolServerIP(IPAddress server_ip){ + this->_poolServerIP = server_ip; + this->_poolServerName = NULL; +} + +void NTPClient::setTimeout(uint16_t t_ms){ + this->_ntp_timeout=t_ms; } void NTPClient::sendNTPPacket() { diff --git a/NTPClient.h b/NTPClient.h index a31d32f..608b4fc 100755 --- a/NTPClient.h +++ b/NTPClient.h @@ -7,6 +7,7 @@ #define SEVENZYYEARS 2208988800UL #define NTP_PACKET_SIZE 48 #define NTP_DEFAULT_LOCAL_PORT 1337 +#define DEBUG_NTPClient class NTPClient { private: @@ -21,7 +22,11 @@ class NTPClient { unsigned long _updateInterval = 60000; // In ms unsigned long _currentEpoc = 0; // In s - unsigned long _lastUpdate = 0; // In ms + float _current_epoc_dec = 0; // In s, decimal part of current epoc + uint32_t _lastUpdate = 0xff000000;// In ms + + uint16_t _ntp_timeout = 1000; // In ms + uint32_t _last_fail = 0xffff0000; // In ms byte _packetBuffer[NTP_PACKET_SIZE]; @@ -49,6 +54,20 @@ class NTPClient { */ void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535); + /** + * clear time server and set ip + * + * @param ServerIP + */ + void setPoolServerIP(IPAddress server_ip); + + /** + * Set ntp timeout, recommand not above 1000ms + * + * @param t_ms + */ + void setTimeout(uint16_t t_ms); + /** * Starts the underlying UDP client with the default local port */ @@ -63,9 +82,12 @@ class NTPClient { * This should be called in the main loop of your application. By default an update from the NTP Server is only * made every 60 seconds. This can be configured in the NTPClient constructor. * - * @return true on success, false on failure + * @return 1(true) on updated and success + * 0(false) on updated and failure + * 2 on not time to update + * 3 on it's time to update but last failed was just happen, so it decided to wait more */ - bool update(); + int8_t update(); /** * This will force the update from the NTP Server. @@ -107,6 +129,11 @@ class NTPClient { */ unsigned long getEpochTime() const; + /** + * @return ms of this second, in ms + */ + float get_millis() const; + /** * Stops the underlying UDP client */ From 4a2c617513cb697a4366d61f1edd48630c6633f0 Mon Sep 17 00:00:00 2001 From: WhymustIhaveaname <38423345+WhymustIhaveaname@users.noreply.github.com> Date: Fri, 24 Apr 2020 08:40:02 +0100 Subject: [PATCH 2/4] Add files via upload --- examples/ntp_demo.ino | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 examples/ntp_demo.ino diff --git a/examples/ntp_demo.ino b/examples/ntp_demo.ino new file mode 100644 index 0000000..08568a6 --- /dev/null +++ b/examples/ntp_demo.ino @@ -0,0 +1,94 @@ +// change next line to use with another board/shield +#include +//#include +//#include +//#include +#include +#include "NTPClient.h" + +WiFiUDP ntpUDP; +NTPClient my_time_client(ntpUDP); + +void connect_wifi(char * ssid,char * password){ + Serial.print("wifi connecting..."); + WiFi.begin(ssid,password); + while(WiFi.status()!= WL_CONNECTED){ + delay(1000); + Serial.print("."); + } + + Serial.println("\nwifi connected!"); + Serial.print("ip: "); + Serial.println(WiFi.localIP()); + Serial.print("netmask: "); + Serial.println(WiFi.subnetMask()); + Serial.print("gateway: "); + Serial.println(WiFi.gatewayIP()); + Serial.print("channel: "); + Serial.println(WiFi.channel()); + Serial.print("auto-reconnect: "); + Serial.println(WiFi.getAutoReconnect()); +} + +inline void sync_time(){ + my_time_client.begin(); + my_time_client.setTimeOffset(28800); + my_time_client.setUpdateInterval(20000); + //my_time_client.setPoolServerName("0.ubuntu.pool.ntp.org"); + my_time_client.setPoolServerName("192.168.1.200"); + //smaller timeout will give you more accuracy + //but also larger possibility to fail + my_time_client.setTimeout(800); + Serial.println("syncing..."); + + while(my_time_client.update()!=1){ + delay(2000); + my_time_client.forceUpdate(); + } + + Serial.print("success: "); + Serial.println(my_time_client.getFormattedTime()); +} + +void setup(){ + Serial.begin(230400); + Serial.println("serial inited"); + + connect_wifi((char *)"ssid",(char *)"pwd"); + sync_time(); + + Serial.println("ready!"); +} + +String s_last_time="s_last_time"; + +void loop(){ + String s_time=my_time_client.getFormattedTime(); + if(s_time!=s_last_time){ + Serial.print("a second passed "); + Serial.print(s_time);Serial.print(" "); + Serial.print(my_time_client.get_millis(),3); + Serial.println("ms"); + s_last_time=s_time; + + //please do not update too frequently + int8_t re=my_time_client.update(); + if(re==0){ + Serial.println("0: sync but failed"); + delay(500); + }else if(re==1){ + Serial.println("1: sync and suc"); + }else if(re==2){ + ;//Serial.println("2: not time to sync"); + }else if(re==3){ + Serial.println("3: last failed was just happen"); + }else{ + Serial.print("return value error: "); + Serial.println(re); + } + } + + //float ms=my_time_client.get_millis(); + + delay(1); +} \ No newline at end of file From 1d64f94a8a0c563baf19584e2c0419342158a9be Mon Sep 17 00:00:00 2001 From: WhymustIhaveaname <38423345+WhymustIhaveaname@users.noreply.github.com> Date: Sat, 25 Apr 2020 06:53:15 +0100 Subject: [PATCH 3/4] Add files via upload --- NTPClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NTPClient.cpp b/NTPClient.cpp index e7ff0d6..2d5b2c2 100755 --- a/NTPClient.cpp +++ b/NTPClient.cpp @@ -197,7 +197,7 @@ bool NTPClient::isTimeSet() const { unsigned long NTPClient::getEpochTime() const { return this->_timeOffset + // User offset this->_currentEpoc + // Epoch returned by the NTP server - ((millis() - this->_lastUpdate + (int)(this->_current_epoc_dec*1000)) / 1000); // Time since last update + ((millis() - this->_lastUpdate + this->_current_epoc_dec*1000)/1000.0); // Time since last update } float NTPClient::get_millis() const{ From e4d04dd53cb3f07eed06fb785c35d0e398692540 Mon Sep 17 00:00:00 2001 From: tickelton Date: Wed, 26 May 2021 21:07:45 +0200 Subject: [PATCH 4/4] Adds support for fractional seconds * Rebases WhymustIhaveaname:master to arduino-libraries:master. * Fixes issues with Spell Check action. * Fixes HiRes example compilation. * Refactors HiRes example to be more idiomatic as compared to the existing examples. * Fixes several line ending and white space inconsistencies. --- NTPClient.cpp | 14 +++--- NTPClient.h | 2 +- examples/HiRes/HiRes.ino | 75 ++++++++++++++++++++++++++++++++ examples/ntp_demo.ino | 94 ---------------------------------------- 4 files changed, 85 insertions(+), 100 deletions(-) create mode 100644 examples/HiRes/HiRes.ino delete mode 100644 examples/ntp_demo.ino diff --git a/NTPClient.cpp b/NTPClient.cpp index 2d5b2c2..7c3c0f2 100755 --- a/NTPClient.cpp +++ b/NTPClient.cpp @@ -82,15 +82,19 @@ void NTPClient::begin(unsigned int port) { } bool NTPClient::forceUpdate() { + #ifdef DEBUG_NTPClient + Serial.println("Update from NTP Server"); + #endif + // flush any existing packets while(this->_udp->parsePacket() != 0) this->_udp->flush(); - uint32_t tik,tok; //tik,tok to record wait time, replace timeout + uint32_t tik,tok; //tik,tok to record wait time this->sendNTPPacket(); tik=millis(); #ifdef DEBUG_NTPClient - Serial.println("sent ntp packet"); + Serial.println("Sent ntp packet"); #endif // Wait till data is there or timeout... @@ -143,14 +147,14 @@ bool NTPClient::forceUpdate() { Serial.print(high_word,HEX);Serial.print(", "); Serial.println(transmit_dec,6); #endif - + float ping_delay; ping_delay=(tok-tik)/1000.0-(transmit_int-receive_int)-(transmit_dec-receive_dec); ping_delay/=2.0; if(ping_delay<=0){ Serial.println("ERROR: ping_delay < 0.0!"); } - + this->_lastUpdate=tok; this->_currentEpoc=transmit_int - SEVENZYYEARS ; this->_current_epoc_dec=ping_delay+transmit_dec; @@ -179,7 +183,7 @@ int8_t NTPClient::update() { } } }else{ //if overflowed - if(now+0xffffffff-this->_lastUpdate >= this->_updateInterval){ + if(now+0xffffffff-this->_lastUpdate >= this->_updateInterval){ if(now+0xffffffff-this->_last_fail >= 1500){ return this->forceUpdate(); }else{ diff --git a/NTPClient.h b/NTPClient.h index 608b4fc..72af433 100755 --- a/NTPClient.h +++ b/NTPClient.h @@ -62,7 +62,7 @@ class NTPClient { void setPoolServerIP(IPAddress server_ip); /** - * Set ntp timeout, recommand not above 1000ms + * Set ntp timeout (recommendation < 1000ms) * * @param t_ms */ diff --git a/examples/HiRes/HiRes.ino b/examples/HiRes/HiRes.ino new file mode 100644 index 0000000..73925c2 --- /dev/null +++ b/examples/HiRes/HiRes.ino @@ -0,0 +1,75 @@ +#include +// change next line to use with another board/shield +#include +//#include +//#include +#include + +const char *ssid = ""; +const char *password = ""; + +WiFiUDP ntpUDP; + +// You can specify the time server pool and the offset (in seconds, can be +// changed later with setTimeOffset() ). Additionally you can specify the +// update interval (in milliseconds, can be changed using setUpdateInterval() ). +NTPClient my_time_client(ntpUDP, "europe.pool.ntp.org", 28800, 20000); + +inline void sync_time(){ + my_time_client.begin(); + //smaller timeout will give you more accuracy + //but also larger possibility to fail + my_time_client.setTimeout(800); + Serial.println("syncing..."); + + while(my_time_client.update()!=1){ + delay(2000); + my_time_client.forceUpdate(); + } + + Serial.print("success: "); + Serial.println(my_time_client.getFormattedTime()); +} + +void setup(){ + Serial.begin(115200); + + WiFi.begin(ssid, password); + while ( WiFi.status() != WL_CONNECTED ) { + delay ( 500 ); + Serial.print ( "." ); + } + + sync_time(); +} + +String s_last_time="s_last_time"; + +void loop(){ + String s_time=my_time_client.getFormattedTime(); + if(s_time!=s_last_time){ + Serial.print("a second passed "); + Serial.print(s_time);Serial.print(" "); + Serial.print(my_time_client.get_millis(),3); + Serial.println("ms"); + s_last_time=s_time; + + //please do not update too frequently + int8_t re=my_time_client.update(); + if(re==0){ + Serial.println("0: sync but failed"); + delay(500); + }else if(re==1){ + Serial.println("1: sync and suc"); + }else if(re==2){ + ;//Serial.println("2: not time to sync"); + }else if(re==3){ + Serial.println("3: last failed was just happen"); + }else{ + Serial.print("return value error: "); + Serial.println(re); + } + } + + delay(1); +} diff --git a/examples/ntp_demo.ino b/examples/ntp_demo.ino deleted file mode 100644 index 08568a6..0000000 --- a/examples/ntp_demo.ino +++ /dev/null @@ -1,94 +0,0 @@ -// change next line to use with another board/shield -#include -//#include -//#include -//#include -#include -#include "NTPClient.h" - -WiFiUDP ntpUDP; -NTPClient my_time_client(ntpUDP); - -void connect_wifi(char * ssid,char * password){ - Serial.print("wifi connecting..."); - WiFi.begin(ssid,password); - while(WiFi.status()!= WL_CONNECTED){ - delay(1000); - Serial.print("."); - } - - Serial.println("\nwifi connected!"); - Serial.print("ip: "); - Serial.println(WiFi.localIP()); - Serial.print("netmask: "); - Serial.println(WiFi.subnetMask()); - Serial.print("gateway: "); - Serial.println(WiFi.gatewayIP()); - Serial.print("channel: "); - Serial.println(WiFi.channel()); - Serial.print("auto-reconnect: "); - Serial.println(WiFi.getAutoReconnect()); -} - -inline void sync_time(){ - my_time_client.begin(); - my_time_client.setTimeOffset(28800); - my_time_client.setUpdateInterval(20000); - //my_time_client.setPoolServerName("0.ubuntu.pool.ntp.org"); - my_time_client.setPoolServerName("192.168.1.200"); - //smaller timeout will give you more accuracy - //but also larger possibility to fail - my_time_client.setTimeout(800); - Serial.println("syncing..."); - - while(my_time_client.update()!=1){ - delay(2000); - my_time_client.forceUpdate(); - } - - Serial.print("success: "); - Serial.println(my_time_client.getFormattedTime()); -} - -void setup(){ - Serial.begin(230400); - Serial.println("serial inited"); - - connect_wifi((char *)"ssid",(char *)"pwd"); - sync_time(); - - Serial.println("ready!"); -} - -String s_last_time="s_last_time"; - -void loop(){ - String s_time=my_time_client.getFormattedTime(); - if(s_time!=s_last_time){ - Serial.print("a second passed "); - Serial.print(s_time);Serial.print(" "); - Serial.print(my_time_client.get_millis(),3); - Serial.println("ms"); - s_last_time=s_time; - - //please do not update too frequently - int8_t re=my_time_client.update(); - if(re==0){ - Serial.println("0: sync but failed"); - delay(500); - }else if(re==1){ - Serial.println("1: sync and suc"); - }else if(re==2){ - ;//Serial.println("2: not time to sync"); - }else if(re==3){ - Serial.println("3: last failed was just happen"); - }else{ - Serial.print("return value error: "); - Serial.println(re); - } - } - - //float ms=my_time_client.get_millis(); - - delay(1); -} \ No newline at end of file