Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-works the update() method to avoid blocking #90

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 60 additions & 33 deletions NTPClient.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* The MIT License (MIT)
* Copyright (c) 2015 by Fabrice Weinberg
* Original work Copyright (c) 2015 by Fabrice Weinberg
* Modified work Copyright (c) 2020 by Thomas Haggett
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -82,48 +83,74 @@ void NTPClient::begin(int port) {
}

bool NTPClient::forceUpdate() {
#ifdef DEBUG_NTPClient
Serial.println("Update from NTP Server");
#endif
this->_lastUpdate = 0;
this->_requestSent = 0;
this->_requestDelay = 1;
return true;
}

// flush any existing packets
while(this->_udp->parsePacket() != 0)
this->_udp->flush();
#define REQUEST_TIMEOUT 1000UL

this->sendNTPPacket();
bool NTPClient::update() {
int now = millis();

// Wait till data is there or timeout...
byte timeout = 0;
int cb = 0;
do {
delay ( 10 );
cb = this->_udp->parsePacket();
if (timeout > 100) return false; // timeout after 1000 ms
timeout++;
} while (cb == 0);
if(!this->_udpSetup)
this->begin();

this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
// are we due to send a request?
if(this->_lastUpdate > 0 && now < this->_lastUpdate + this->_updateInterval) {
// update isn't due. carry on.
return false;
}

this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
// we're due an update - have we sent a request and it has timed out,
// or not actually sent a request yet?
if(this->_requestSent == 0 || now > this->_requestSent + this->_requestDelay + REQUEST_TIMEOUT) {
// if we had already sent a request, let's bump up the _requestDelay so we don't constantly
// hammer a potentially down NTP server!
if(this->_requestSent > 0) {
this->_requestDelay *= 2;
if(this->_requestDelay > 30000)
this->_requestDelay = 30000;
} else {
// this is the first time we're attempting a send.
// purge any old packets that might be buffered
while(this->_udp->parsePacket() != 0) {
this->_udp->flush();
}
}

// Right. Send an NTP packet!
// Serial.printf("Sending an NTP packet (timeout=%i)!\n", this->_requestDelay + REQUEST_TIMEOUT);
this->sendNTPPacket();

// remember when we last sent a request
this->_requestSent = now;
}

unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_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;
// check for any replies!
int length = this->_udp->parsePacket();
if( length > 0 ) {
Serial.println("Got an NTP reply!");
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
this->_udp->flush();

this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_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;

return true; // return true after successful update
}
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;

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->begin(); // setup the UDP client if needed
return this->forceUpdate();
// cleanup and reset our state
this->_requestSent = 0;
this->_requestDelay = 1;
this->_lastUpdate = now;
return true;
}
return false; // return false if update does not occur

return false;
}

unsigned long NTPClient::getEpochTime() const {
Expand Down
3 changes: 3 additions & 0 deletions NTPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class NTPClient {
unsigned long _currentEpoc = 0; // In s
unsigned long _lastUpdate = 0; // In ms

unsigned long _requestSent = 0; // in ms (when the last request was sent)
unsigned long _requestDelay = 1; // in ms (a cumulative delay to slow down constant failures)

byte _packetBuffer[NTP_PACKET_SIZE];

void sendNTPPacket();
Expand Down