Tiny SNTP(NTP) Client

Dependencies:   EthernetNetIf mbed

Revision:
0:41e7cfdbd23a
Child:
1:d3c1871be1e9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinySNTP.cpp	Thu Jul 21 17:53:11 2011 +0000
@@ -0,0 +1,143 @@
+/*
+ * 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;
+}