Tiny SNTP(NTP) Client
Dependencies: EthernetNetIf mbed
Diff: TinySNTP.cpp
- 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; +}