NTP Client for the mbed networking libraries. The small change to this version is that there can be only one cause for the return value zero.

Dependents:   WattEye

Fork of NTPClient by Donatien Garnier

Revision:
9:2f607bafc29e
Parent:
8:802277794640
--- a/NTPClient.cpp	Thu Nov 26 18:20:56 2015 +0000
+++ b/NTPClient.cpp	Sat Jan 16 20:47:33 2016 +0000
@@ -16,27 +16,47 @@
  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
+#include "mbed.h" //time() and set_time()
 
-//Debug is disabled by default
-#if 0
-//Enable debug
-#define __DEBUG__
+//#define DEBUG "NTPc"
+
+#if (defined(DEBUG))
 #include <cstdio>
-#define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
-#define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
-#define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+static void HexDump(const char * title, const uint8_t * p, int count)
+{
+    int i;
+    char buf[100] = "0000: ";
+
+    if (*title)
+        INFO("%s", title);
+    for (i=0; i<count; ) {
+        sprintf(buf + strlen(buf), "%02X ", *(p+i));
+        if ((++i & 0x0F) == 0x00) {
+            INFO("%s", buf);
+            if (i < count)
+                sprintf(buf, "%04X: ", i);
+            else
+                buf[0] = '\0';
+        }
+    }
+    if (strlen(buf))
+        INFO("%s", buf);
+}
 #else
 //Disable debug
-#define DBG(x, ...)
+#define INFO(x, ...)
 #define WARN(x, ...)
 #define ERR(x, ...)
+#define HexDump(a,b,c)
 #endif
 
 #include "NTPClient.h"
 
 #include "UDPSocket.h"
 
-#include "mbed.h" //time() and set_time()
 
 #define NTP_PORT 123
 #define NTP_CLIENT_PORT 0 //Random port
@@ -49,14 +69,14 @@
 
 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
 {
-#ifdef __DEBUG__
+#ifdef DEBUG
     time_t ctTime;
     ctTime = time(NULL);
-    DBG("Time is set to (UTC): %s", ctime(&ctTime));
+    INFO("Time is currently (UTC): %s", ctime(&ctTime));
 #endif
 
     //Create & bind socket
-    DBG("Binding socket");
+    INFO("Binding socket");
     m_sock.bind(0); //Bind to a random port
 
     m_sock.set_blocking(false, timeout); //Set not blocking
@@ -64,7 +84,7 @@
     struct NTPPacket pkt;
 
     //Now ping the server and wait for response
-    DBG("Ping");
+    INFO("Ping");
     //Prepare NTP Packet:
     pkt.li = 0; //Leap Indicator : No warning
     pkt.vn = 4; //Version Number : 4
@@ -81,15 +101,19 @@
     pkt.origTm_s = 0;
     pkt.rxTm_s = 0;
     pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE
-
+    INFO("pkt.txTm_s = %u", ntohl(pkt.txTm_s) );
     pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
 
+    HexDump("NTP Post", (uint8_t *)&pkt, sizeof(NTPPacket));
+    
     Endpoint outEndpoint;
-
+    INFO("outEndpoint instantiated");
+    
     if( outEndpoint.set_address(host, port) < 0) {
         m_sock.close();
         return NTP_DNS;
     }
+    INFO("outEndpoint: %s:%d", outEndpoint.get_address(), outEndpoint.get_port());
 
     //Set timeout, non-blocking and wait using select
     int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
@@ -101,20 +125,25 @@
 
     //Read response
     Endpoint inEndpoint;
-
+    INFO(" inEndpoint instantiated: %s.", inEndpoint.get_address());
+    
     // Set the inEndpoint address property
     inEndpoint.set_address(outEndpoint.get_address(), 0);
 
-    DBG("Pong");
+    INFO(" inEndpoint: %s", inEndpoint.get_address());
+
+    INFO("Pong");
+    int loopLimit = 20;  // semi-randomly selected so it doesn't hang forever here...
     do {
-        ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
+        ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) );
         if(ret < 0) {
             ERR("Could not receive packet");
             m_sock.close();
             return NTP_CONN;
         }
-        DBG(".");
-    } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 );
+        INFO(".");
+        loopLimit--;
+    } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 && loopLimit > 0);
 
     if(ret < (int)sizeof(NTPPacket)) { //TODO: Accept chunks
         ERR("Receive packet size does not match");
@@ -128,6 +157,8 @@
         return NTP_PRTCL;
     }
 
+    HexDump("NTP Info", (uint8_t *)&pkt, sizeof(NTPPacket));
+
     //Correct Endianness
     pkt.refTm_s = ntohl( pkt.refTm_s );
     pkt.refTm_f = ntohl( pkt.refTm_f );
@@ -140,15 +171,31 @@
 
     //Compute offset, see RFC 4330 p.13
     uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
-    int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
-    DBG("Sent @%ul", pkt.txTm_s);
-    DBG("Offset: %lld", offset);
+    INFO("destTm_s = %u", destTm_s);
+    INFO("pkt.txTm_s = %u", pkt.txTm_s );
+    
+    // Modification by David Smart
+    // The setTime function was computing the offset incorrectly as the value was promoted to 64-bit.
+    // The side effect was that a negative offset ended up as a very large positive (e.g. jump from 
+    // 2016 to 2084). This change revises that computation.
+    int64_t offset = ( ((int64_t)pkt.rxTm_s - pkt.origTm_s ) + ((int64_t) pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
+    
+    // delay is not needed, this was for diagnostic purposes only.
+    //int64_t delay = ((int64_t) destTm_s - pkt.origTm_s) - ((int64_t) pkt.txTm_s - pkt.rxTm_s);
+    INFO("txTm_s   @%u", pkt.txTm_s);
+    INFO("origTm_s @%u", pkt.origTm_s);
+    INFO("rxTm_s   @%u", pkt.rxTm_s);
+    INFO("destTm_s @%u", destTm_s);
+    INFO("Offset: %lld", offset);
+    //INFO("Delay:  %lld", delay);
+    
+    INFO(" time:    %u", time(NULL));
     //Set time accordingly
     set_time( time(NULL) + offset );
 
 #ifdef __DEBUG__
     ctTime = time(NULL);
-    DBG("Time is now (UTC): %s", ctime(&ctTime));
+    INFO("Time is now (UTC): %s", ctime(&ctTime));
 #endif
 
     m_sock.close();