Tiny SNTP(NTP) Client

Dependencies:   EthernetNetIf mbed

Revision:
1:d3c1871be1e9
Parent:
0:41e7cfdbd23a
--- a/TinySNTP.cpp	Thu Jul 21 17:53:11 2011 +0000
+++ b/TinySNTP.cpp	Thu Jul 28 17:23:43 2011 +0000
@@ -1,143 +1,170 @@
-/*
- * mbed Tiny SNTP(NTP) Client
- * Copyright (c) 2011 Hiroshi Suga
- * Released under the MIT License: http://mbed.org/license/mit
- */
-
-/** @file
- * @brief Tiny DNS Resolver
- */
-
-#include "mbed.h"
-#include "EthernetNetIf.h"
-#include "UDPSocket.h"
-#include "DNSRequest.h"
-#include "TinySNTP.h"
-
-// host to network short
-#define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
-#define ntohs( x ) htons(x)
-// host to network long
-#define htonl( x ) ( (( (x) << 24 ) & 0xFF000000)  \
-                   | (( (x) <<  8 ) & 0x00FF0000)  \
-                   | (( (x) >>  8 ) & 0x0000FF00)  \
-                   | (( (x) >> 24 ) & 0x000000FF)  )
-#define ntohl( x ) htonl(x)
-
-static UDPSocket *sntp;
-static volatile unsigned long sntptime;
-extern EthernetNetIf eth;
-
-int createSntpRequest (char *buf) {
-    struct SNTPPacket *sntp;
-
-    sntp = (struct SNTPPacket *)buf;
-    memset(sntp, 0, sizeof(struct SNTPPacket));
-    sntp->info = 0x1b; // Ver.3, client
-    sntp->txTm_s = htonl(NTP_TIMESTAMP_DELTA + time(NULL));
-
-    return sizeof(struct SNTPPacket);
-}
-
-int getSntpResponse (const char *buf, uint32_t *tim) {
-    struct SNTPPacket *sntp;
-    uint32_t now;
-//    long int delay, offset;
-
-    sntp = (struct SNTPPacket *)buf;
-    if ((sntp->info & 0x3f) == 0x1c || (sntp->info & 0x3f) == 0x24) {
-        // Ver.3or4, Server
-
-        now = htonl(NTP_TIMESTAMP_DELTA + time(NULL));
-/*
-        delay = (now - sntp->origTm_s) - (sntp->rxTm_s - sntp->txTm_s);
-        offset = ((sntp->rxTm_s - sntp->origTm_s) + (sntp->txTm_s - now));
-
-        *tim = ntohl(sntp->txTm_s) - NTP_TIMESTAMP_DELTA + (delay / 2);
-*/
-        *tim = ntohl(sntp->txTm_s) - NTP_TIMESTAMP_DELTA;
-#ifdef DEBUG
-        printf("now %08x\r\n", ntohl(now));
-        printf("ref %08x\r\n", ntohl(sntp->refTm_s));
-        printf("orig %08x\r\n", ntohl(sntp->origTm_s));
-        printf("rx %08x\r\n", ntohl(sntp->rxTm_s));
-        printf("tx %08x\r\n", ntohl(sntp->txTm_s));
-//        printf("delay %d / offset %d\r\n", delay, offset);
-#endif
-        return 0;
-    }
-
-    return -1;
-}
-
-void isr_sntp (UDPSocketEvent e) {
-    char buf[100];
-    Host dsthost;
-    int len;
-
-    if (e == UDPSOCKET_READABLE) {
-        // recv responce;
-        len = sntp->recvfrom(buf, sizeof(buf), &dsthost);
-#ifdef DEBUG
-        for (int i = 0; i < len; i ++) {
-            printf(" %02x", (unsigned char)buf[i]);
-        }
-        puts("\r");
-#endif
-        if (len >= sizeof(struct SNTPPacket)) {
-            getSntpResponse(buf, (uint32_t*)&sntptime);
-        }
-    }
-}
-
-int ntpdate (const char* name, uint32_t *tim) {
-    UDPSocketErr err;
-    Host myhost, sntphost;
-    char buf[100];
-    int i, len;
-    DNSRequest dns;
-    DNSRequestErr dnsErr;
-
-    sntptime = 0;
-    sntp = new UDPSocket;
-    sntp->setOnEvent(isr_sntp);
-
-    // bind
-    myhost.setIp(eth.getIp());
-    myhost.setPort(NTP_SRC_PORT);
-    err = sntp->bind(myhost);
-    if (err != UDPSOCKET_OK) goto exit;
-
-    // send request
-    sntphost.setName(name);
-    sntphost.setPort(NTP_PORT);
-    dnsErr = dns.resolve(&sntphost);
-    if (dnsErr != DNS_OK) goto exit;
-    len = createSntpRequest(buf);
-#ifdef DEBUG
-    for (int i = 0; i < len; i ++) {
-        printf(" %02x", (unsigned char)buf[i]);
-    }
-    puts("\r");
-#endif
-    sntp->sendto(buf, len, &sntphost);
-
-    // wait responce
-    for (i = 0; i < NTP_TIMEOUT / 10; i ++) {
-        if (sntptime) {
-            *tim = sntptime;
-            break;
-        }
-        if (i % 500 == 499) {
-            sntp->sendto(buf, len, &sntphost);
-        }
-        Net::poll();
-        wait_ms(10);
-    }
-
-exit:
-    sntp->resetOnEvent();
-    delete sntp;
-
-    return sntptime ? 0 : -1;
-}
+/*
+ * mbed Tiny SNTP(NTP) Client
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief Tiny DNS Resolver
+ */
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "DNSRequest.h"
+#include "TinySNTP.h"
+
+// host to network short
+#define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
+#define ntohs( x ) htons(x)
+// host to network long
+#define htonl( x ) ( (( (x) << 24 ) & 0xFF000000)  \
+                   | (( (x) <<  8 ) & 0x00FF0000)  \
+                   | (( (x) >>  8 ) & 0x0000FF00)  \
+                   | (( (x) >> 24 ) & 0x000000FF)  )
+#define ntohl( x ) htonl(x)
+
+static UDPSocket *sntp;
+static volatile unsigned long sntptime;
+static volatile int dns_status;
+extern EthernetNetIf eth;
+
+int createSntpRequest (char *buf) {
+    struct SNTPPacket *sntp;
+
+    sntp = (struct SNTPPacket *)buf;
+    memset(sntp, 0, sizeof(struct SNTPPacket));
+    sntp->info = 0x1b; // Ver.3, client
+    sntp->txTm_s = htonl(NTP_TIMESTAMP_DELTA + time(NULL));
+
+    return sizeof(struct SNTPPacket);
+}
+
+int getSntpResponse (const char *buf, uint32_t *tim) {
+    struct SNTPPacket *sntp;
+    uint32_t now;
+//    long int delay, offset;
+
+    sntp = (struct SNTPPacket *)buf;
+    if ((sntp->info & 0x3f) == 0x1c || (sntp->info & 0x3f) == 0x24) {
+        // Ver.3or4, Server
+
+        now = htonl(NTP_TIMESTAMP_DELTA + time(NULL));
+/*
+        delay = (now - sntp->origTm_s) - (sntp->rxTm_s - sntp->txTm_s);
+        offset = ((sntp->rxTm_s - sntp->origTm_s) + (sntp->txTm_s - now));
+
+        *tim = ntohl(sntp->txTm_s) - NTP_TIMESTAMP_DELTA + (delay / 2);
+*/
+        *tim = ntohl(sntp->txTm_s) - NTP_TIMESTAMP_DELTA;
+#ifdef DEBUG
+        printf("now %08x\r\n", ntohl(now));
+        printf("ref %08x\r\n", ntohl(sntp->refTm_s));
+        printf("orig %08x\r\n", ntohl(sntp->origTm_s));
+        printf("rx %08x\r\n", ntohl(sntp->rxTm_s));
+        printf("tx %08x\r\n", ntohl(sntp->txTm_s));
+//        printf("delay %d / offset %d\r\n", delay, offset);
+#endif
+        return 0;
+    }
+
+    return -1;
+}
+
+void isr_dns (DNSReply r) {
+
+#ifdef DEBUG
+    printf("dns(%d)\r\n", r);
+#endif
+    if (DNS_FOUND) {
+        dns_status = 1;
+    } else {
+        dns_status = -1;
+    }
+}
+
+void isr_sntp (UDPSocketEvent e) {
+    char buf[100];
+    Host dsthost;
+    int len;
+
+    if (e == UDPSOCKET_READABLE) {
+        // recv responce;
+        len = sntp->recvfrom(buf, sizeof(buf), &dsthost);
+#ifdef DEBUG
+        for (int i = 0; i < len; i ++) {
+            printf(" %02x", (unsigned char)buf[i]);
+        }
+        puts("\r");
+#endif
+        if (len >= sizeof(struct SNTPPacket)) {
+            getSntpResponse(buf, (uint32_t*)&sntptime);
+        }
+    }
+}
+
+int ntpdate (const char* name, uint32_t *tim) {
+    UDPSocketErr err;
+    Host sntphost;
+    Timer timeout;
+    char buf[100];
+    int i, len;
+
+    sntptime = 0;
+    sntp = new UDPSocket;
+    sntp->setOnEvent(isr_sntp);
+
+    sntphost.setName(name);
+    {
+        // resolv
+        DNSRequest dns;
+        dns_status = 0;
+        dns.setOnReply(isr_dns);
+        if (dns.resolve(&sntphost) != DNS_OK) goto exit;
+        timeout.reset();
+        timeout.start();
+        while (timeout.read_ms() < NTP_TIMEOUT) {
+            if (dns_status) break;
+            Net::poll();
+        }
+        timeout.stop();
+        if (dns_status <= 0) goto exit;
+#ifdef DEBUG
+        printf("%s [%d.%d.%d.%d]\r\n", sntphost.getName(), (unsigned char)sntphost.getIp()[0], (unsigned char)sntphost.getIp()[1], (unsigned char)sntphost.getIp()[2], (unsigned char)sntphost.getIp()[3]);
+#endif
+    }
+    sntphost.setPort(NTP_PORT);
+
+    // send request
+    len = createSntpRequest(buf);
+#ifdef DEBUG
+    for (int i = 0; i < len; i ++) {
+        printf(" %02x", (unsigned char)buf[i]);
+    }
+    puts("\r");
+#endif
+    sntp->sendto(buf, len, &sntphost);
+
+    // wait responce
+    i = 0;
+    timeout.reset();
+    timeout.start();
+    while (timeout.read_ms() < NTP_TIMEOUT) {
+        if (sntptime) {
+            *tim = sntptime;
+            break;
+        }
+        if (timeout.read_ms() / 5000 < i) {
+            sntp->sendto(buf, len, &sntphost);
+            i ++;
+        }
+        Net::poll();
+    }
+    timeout.stop();
+
+exit:
+    sntp->resetOnEvent();
+    delete sntp;
+
+    return sntptime ? 0 : -1;
+}