]> granicus.if.org Git - esp-idf/commitdiff
components/lwip: add SNTP function feature
authorliuhan <liuhan@espressif.com>
Fri, 26 Aug 2016 06:54:40 +0000 (14:54 +0800)
committerWu Jian Gang <wujiangang@espressif.com>
Thu, 1 Sep 2016 11:22:36 +0000 (19:22 +0800)
Develop and Compile SNTP function based on LWIP core code, see lwip/apps/sntp file.

components/lwip/apps/sntp/sntp.c [new file with mode: 0644]
components/lwip/apps/sntp/sntp_time.c [new file with mode: 0644]
components/lwip/include/lwip/apps/sntp.h [new file with mode: 0644]
components/lwip/include/lwip/apps/sntp_opts.h [new file with mode: 0644]
components/lwip/include/lwip/apps/sntp_time.h [new file with mode: 0644]

diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c
new file mode 100644 (file)
index 0000000..1dee35e
--- /dev/null
@@ -0,0 +1,716 @@
+/**
+ * @file
+ * SNTP client module
+ *
+ * This is simple "SNTP" client for the lwIP raw API.
+ * It is a minimal implementation of SNTPv4 as specified in RFC 4330.
+ *
+ * For a list of some public NTP servers, see this link :
+ * http://support.ntp.org/bin/view/Servers/NTPPoolServers
+ *
+ * @todo:
+ * - set/change servers at runtime
+ * - complete SNTP_CHECK_RESPONSE checks 3 and 4
+ * - support broadcast/multicast mode?
+ */
+
+/*
+ * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Frédéric Bernon, Simon Goldschmidt
+ */
+
+#include "apps/sntp.h"
+
+#include "lwip/opt.h"
+#include "lwip/timers.h"
+#include "lwip/udp.h"
+#include "lwip/dns.h"
+#include "lwip/ip_addr.h"
+#include "lwip/pbuf.h"
+#include "lwip/dhcp.h"
+
+#include <string.h>
+#include <time.h>
+
+#if LWIP_UDP
+
+/* Handle support for more than one server via SNTP_MAX_SERVERS */
+#if SNTP_MAX_SERVERS > 1
+#define SNTP_SUPPORT_MULTIPLE_SERVERS 1
+#else /* NTP_MAX_SERVERS > 1 */
+#define SNTP_SUPPORT_MULTIPLE_SERVERS 0
+#endif /* NTP_MAX_SERVERS > 1 */
+
+#if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK)
+#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
+#endif
+
+/* Configure behaviour depending on microsecond or second precision */
+#ifdef SNTP_SET_SYSTEM_TIME_US
+#define SNTP_CALC_TIME_US           1
+#define SNTP_RECEIVE_TIME_SIZE      2
+#else
+#define SNTP_SET_SYSTEM_TIME_US(sec, us)
+#define SNTP_CALC_TIME_US           0
+#define SNTP_RECEIVE_TIME_SIZE      1
+#endif
+
+
+/* the various debug levels for this file */
+#define SNTP_DEBUG_TRACE        (SNTP_DEBUG | LWIP_DBG_TRACE)
+#define SNTP_DEBUG_STATE        (SNTP_DEBUG | LWIP_DBG_STATE)
+#define SNTP_DEBUG_WARN         (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
+#define SNTP_DEBUG_WARN_STATE   (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
+#define SNTP_DEBUG_SERIOUS      (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
+
+#define SNTP_ERR_KOD                1
+
+/* SNTP protocol defines */
+#define SNTP_MSG_LEN                48
+
+#define SNTP_OFFSET_LI_VN_MODE      0
+#define SNTP_LI_MASK                0xC0
+#define SNTP_LI_NO_WARNING          0x00
+#define SNTP_LI_LAST_MINUTE_61_SEC  0x01
+#define SNTP_LI_LAST_MINUTE_59_SEC  0x02
+#define SNTP_LI_ALARM_CONDITION     0x03 /* (clock not synchronized) */
+
+#define SNTP_VERSION_MASK           0x38
+#define SNTP_VERSION                (4/* NTP Version 4*/<<3)
+
+#define SNTP_MODE_MASK              0x07
+#define SNTP_MODE_CLIENT            0x03
+#define SNTP_MODE_SERVER            0x04
+#define SNTP_MODE_BROADCAST         0x05
+
+#define SNTP_OFFSET_STRATUM         1
+#define SNTP_STRATUM_KOD            0x00
+
+#define SNTP_OFFSET_ORIGINATE_TIME  24
+#define SNTP_OFFSET_RECEIVE_TIME    32
+#define SNTP_OFFSET_TRANSMIT_TIME   40
+
+/* number of seconds between 1900 and 1970 (MSB=1)*/
+#define DIFF_SEC_1900_1970         (2208988800UL)
+/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
+#define DIFF_SEC_1970_2036         (2085978496UL)
+
+/**
+ * SNTP packet format (without optional fields)
+ * Timestamps are coded as 64 bits:
+ * - 32 bits seconds since Jan 01, 1970, 00:00
+ * - 32 bits seconds fraction (0-padded)
+ * For future use, if the MSB in the seconds part is set, seconds are based
+ * on Feb 07, 2036, 06:28:16.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct sntp_msg {
+  PACK_STRUCT_FLD_8(u8_t  li_vn_mode);
+  PACK_STRUCT_FLD_8(u8_t  stratum);
+  PACK_STRUCT_FLD_8(u8_t  poll);
+  PACK_STRUCT_FLD_8(u8_t  precision);
+  PACK_STRUCT_FIELD(u32_t root_delay);
+  PACK_STRUCT_FIELD(u32_t root_dispersion);
+  PACK_STRUCT_FIELD(u32_t reference_identifier);
+  PACK_STRUCT_FIELD(u32_t reference_timestamp[2]);
+  PACK_STRUCT_FIELD(u32_t originate_timestamp[2]);
+  PACK_STRUCT_FIELD(u32_t receive_timestamp[2]);
+  PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* function prototypes */
+static void sntp_request(void *arg);
+
+/** The operating mode */
+static u8_t sntp_opmode;
+
+/** The UDP pcb used by the SNTP client */
+static struct udp_pcb* sntp_pcb;
+/** Names/Addresses of servers */
+struct sntp_server {
+#if SNTP_SERVER_DNS
+  char* name;
+#endif /* SNTP_SERVER_DNS */
+  ip_addr_t addr;
+};
+static struct sntp_server sntp_servers[SNTP_MAX_SERVERS];
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+static u8_t sntp_set_servers_from_dhcp;
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+#if SNTP_SUPPORT_MULTIPLE_SERVERS
+/** The currently used server (initialized to 0) */
+static u8_t sntp_current_server;
+#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+#define sntp_current_server 0
+#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+
+#if SNTP_RETRY_TIMEOUT_EXP
+#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT
+/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */
+static u32_t sntp_retry_timeout;
+#else /* SNTP_RETRY_TIMEOUT_EXP */
+#define SNTP_RESET_RETRY_TIMEOUT()
+#define sntp_retry_timeout SNTP_RETRY_TIMEOUT
+#endif /* SNTP_RETRY_TIMEOUT_EXP */
+
+#if SNTP_CHECK_RESPONSE >= 1
+/** Saves the last server address to compare with response */
+static ip_addr_t sntp_last_server_address;
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+
+#if SNTP_CHECK_RESPONSE >= 2
+/** Saves the last timestamp sent (which is sent back by the server)
+ * to compare against in response */
+static u32_t sntp_last_timestamp_sent[2];
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+
+/**
+ * SNTP processing of received timestamp
+ */
+static void
+sntp_process(u32_t *receive_timestamp)
+{
+  /* convert SNTP time (1900-based) to unix GMT time (1970-based)
+   * if MSB is 0, SNTP time is 2036-based!
+   */
+  u32_t rx_secs = ntohl(receive_timestamp[0]);
+  int is_1900_based = ((rx_secs & 0x80000000) != 0);
+  u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036);
+  time_t tim = t;
+
+#if SNTP_CALC_TIME_US
+  u32_t us = ntohl(receive_timestamp[1]) / 4295;
+  SNTP_SET_SYSTEM_TIME_US(t, us);
+  /* display local time from GMT time */
+  LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us));
+
+#else /* SNTP_CALC_TIME_US */
+
+  /* change system time and/or the update the RTC clock */
+  SNTP_SET_SYSTEM_TIME(t);
+  /* display local time from GMT time */
+  sntp_convert_time(t);
+  LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
+#endif /* SNTP_CALC_TIME_US */
+  LWIP_UNUSED_ARG(tim);
+}
+
+/**
+ * Initialize request struct to be sent to server.
+ */
+static void
+sntp_initialize_request(struct sntp_msg *req)
+{
+  memset(req, 0, SNTP_MSG_LEN);
+  req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
+
+#if SNTP_CHECK_RESPONSE >= 2
+  {
+    u32_t sntp_time_sec, sntp_time_us;
+    /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
+    SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
+    sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970);
+    req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
+    /* we send/save us instead of fraction to be faster... */
+    sntp_last_timestamp_sent[1] = htonl(sntp_time_us);
+    req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
+  }
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+}
+
+/**
+ * Retry: send a new request (and increase retry timeout).
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_retry(void* arg)
+{
+  LWIP_UNUSED_ARG(arg);
+
+  LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n",
+    sntp_retry_timeout));
+
+  /* set up a timer to send a retry and increase the retry delay */
+  sys_timeout(sntp_retry_timeout, sntp_request, NULL);
+
+#if SNTP_RETRY_TIMEOUT_EXP
+  {
+    u32_t new_retry_timeout;
+    /* increase the timeout for next retry */
+    new_retry_timeout = sntp_retry_timeout << 1;
+    /* limit to maximum timeout and prevent overflow */
+    if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&
+        (new_retry_timeout > sntp_retry_timeout)) {
+      sntp_retry_timeout = new_retry_timeout;
+    }
+  }
+#endif /* SNTP_RETRY_TIMEOUT_EXP */
+}
+
+#if SNTP_SUPPORT_MULTIPLE_SERVERS
+/**
+ * If Kiss-of-Death is received (or another packet parsing error),
+ * try the next server or retry the current server and increase the retry
+ * timeout if only one server is available.
+ * (implicitly, SNTP_MAX_SERVERS > 1)
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_try_next_server(void* arg)
+{
+  u8_t old_server, i;
+  LWIP_UNUSED_ARG(arg);
+
+  old_server = sntp_current_server;
+  for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {
+    sntp_current_server++;
+    if (sntp_current_server >= SNTP_MAX_SERVERS) {
+      sntp_current_server = 0;
+    }
+    if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)
+#if SNTP_SERVER_DNS
+        || (sntp_servers[sntp_current_server].name != NULL)
+#endif
+        ) {
+      LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n",
+        (u16_t)sntp_current_server));
+      /* new server: reset retry timeout */
+      SNTP_RESET_RETRY_TIMEOUT();
+      /* instantly send a request to the next server */
+      sntp_request(NULL);
+      return;
+    }
+  }
+  /* no other valid server found */
+  sntp_current_server = old_server;
+  sntp_retry(NULL);
+}
+#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+/* Always retry on error if only one server is supported */
+#define sntp_try_next_server    sntp_retry
+#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */
+
+/** UDP recv callback for the sntp pcb */
+static void
+sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+  u8_t mode;
+  u8_t stratum;
+  u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
+  err_t err;
+
+  LWIP_UNUSED_ARG(arg);
+  LWIP_UNUSED_ARG(pcb);
+
+  /* packet received: stop retry timeout  */
+  sys_untimeout(sntp_try_next_server, NULL);
+  sys_untimeout(sntp_request, NULL);
+
+  err = ERR_ARG;
+#if SNTP_CHECK_RESPONSE >= 1
+  /* check server address and port */
+  if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) &&
+    (port == SNTP_PORT))
+#else /* SNTP_CHECK_RESPONSE >= 1 */
+  LWIP_UNUSED_ARG(addr);
+  LWIP_UNUSED_ARG(port);
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+  {
+    /* process the response */
+    if (p->tot_len == SNTP_MSG_LEN) {
+      pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);
+      mode &= SNTP_MODE_MASK;
+      /* if this is a SNTP response... */
+      if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) ||
+          ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) {
+        pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);
+        if (stratum == SNTP_STRATUM_KOD) {
+          /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
+          err = SNTP_ERR_KOD;
+          LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n"));
+        } else {
+#if SNTP_CHECK_RESPONSE >= 2
+          /* check originate_timetamp against sntp_last_timestamp_sent */
+          u32_t originate_timestamp[2];
+          pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);
+          if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||
+              (originate_timestamp[1] != sntp_last_timestamp_sent[1]))
+          {
+            LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n"));
+          } else
+#endif /* SNTP_CHECK_RESPONSE >= 2 */
+          /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */
+          {
+            /* correct answer */
+            err = ERR_OK;
+            pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
+          }
+        }
+      } else {
+        LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode));
+        /* wait for correct response */
+        err = ERR_TIMEOUT;
+      }
+    } else {
+      LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len));
+    }
+  }
+#if SNTP_CHECK_RESPONSE >= 1
+  else {
+    /* packet from wrong remote address or port, wait for correct response */
+    err = ERR_TIMEOUT;
+  }
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+  pbuf_free(p);
+  if (err == ERR_OK) {
+    sntp_process(receive_timestamp);
+
+    /* Set up timeout for next request (only if poll response was received)*/
+    if (sntp_opmode == SNTP_OPMODE_POLL) {
+      /* Correct response, reset retry timeout */
+      SNTP_RESET_RETRY_TIMEOUT();
+
+      sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);
+      LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n",
+        (u32_t)SNTP_UPDATE_DELAY));
+    }
+  } else if (err != ERR_TIMEOUT) {
+    /* Errors are only processed in case of an explicit poll response */
+    if (sntp_opmode == SNTP_OPMODE_POLL) {
+      if (err == SNTP_ERR_KOD) {
+        /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */
+        sntp_try_next_server(NULL);
+      } else {
+        /* another error, try the same server again */
+        sntp_retry(NULL);
+      }
+    }
+  }
+}
+
+/** Actually send an sntp request to a server.
+ *
+ * @param server_addr resolved IP address of the SNTP server
+ */
+static void
+sntp_send_request(const ip_addr_t *server_addr)
+{
+  struct pbuf* p;
+  p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
+  if (p != NULL) {
+    struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;
+    LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n"));
+    /* initialize request message */
+    sntp_initialize_request(sntpmsg);
+    /* send request */
+    udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);
+    /* free the pbuf after sending it */
+    pbuf_free(p);
+    /* set up receive timeout: try next server or retry on timeout */
+    sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
+#if SNTP_CHECK_RESPONSE >= 1
+    /* save server address to verify it in sntp_recv */
+    ip_addr_set(&sntp_last_server_address, server_addr);
+#endif /* SNTP_CHECK_RESPONSE >= 1 */
+  } else {
+    LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n",
+      (u32_t)SNTP_RETRY_TIMEOUT));
+    /* out of memory: set up a timer to send a retry */
+    sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);
+  }
+}
+
+#if SNTP_SERVER_DNS
+/**
+ * DNS found callback when using DNS names as server address.
+ */
+static void
+sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
+{
+  LWIP_UNUSED_ARG(hostname);
+  LWIP_UNUSED_ARG(arg);
+
+  if (ipaddr != NULL) {
+    /* Address resolved, send request */
+    LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n"));
+    sntp_send_request(ipaddr);
+  } else {
+    /* DNS resolving failed -> try another server */
+    LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n"));
+    sntp_try_next_server(NULL);
+  }
+}
+#endif /* SNTP_SERVER_DNS */
+
+/**
+ * Send out an sntp request.
+ *
+ * @param arg is unused (only necessary to conform to sys_timeout)
+ */
+static void
+sntp_request(void *arg)
+{
+  ip_addr_t sntp_server_address;
+  err_t err;
+
+  LWIP_UNUSED_ARG(arg);
+
+  /* initialize SNTP server address */
+#if SNTP_SERVER_DNS
+  if (sntp_servers[sntp_current_server].name) {
+    /* always resolve the name and rely on dns-internal caching & timeout */
+    ip_addr_set_zero(&sntp_servers[sntp_current_server].addr);
+    err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,
+      sntp_dns_found, NULL);
+    if (err == ERR_INPROGRESS) {
+      /* DNS request sent, wait for sntp_dns_found being called */
+      LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n"));
+      return;
+    } else if (err == ERR_OK) {
+      sntp_servers[sntp_current_server].addr = sntp_server_address;
+    }
+  } else
+#endif /* SNTP_SERVER_DNS */
+  {
+    sntp_server_address = sntp_servers[sntp_current_server].addr;
+    err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK;
+  }
+
+  if (err == ERR_OK) {
+    LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n",
+      ipaddr_ntoa(&sntp_server_address)));
+    sntp_send_request(&sntp_server_address);
+  } else {
+    /* address conversion failed, try another server */
+    LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n"));
+    sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);
+  }
+}
+
+/**
+ * Initialize this module.
+ * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).
+ */
+void
+sntp_init(void)
+{
+#ifdef SNTP_SERVER_ADDRESS
+#if SNTP_SERVER_DNS
+  sntp_setservername(0, SNTP_SERVER_ADDRESS);
+#else
+#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0
+#endif
+#endif /* SNTP_SERVER_ADDRESS */
+
+  if (sntp_pcb == NULL) {
+    sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+    LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);
+    if (sntp_pcb != NULL) {
+      udp_recv(sntp_pcb, sntp_recv, NULL);
+
+      if (sntp_opmode == SNTP_OPMODE_POLL) {
+        SNTP_RESET_RETRY_TIMEOUT();
+#if SNTP_STARTUP_DELAY
+        sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);
+#else
+        sntp_request(NULL);
+#endif
+      } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) {
+        ip_set_option(sntp_pcb, SOF_BROADCAST);
+        udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT);
+      }
+    }
+  }
+}
+
+/**
+ * Stop this module.
+ */
+void
+sntp_stop(void)
+{
+  if (sntp_pcb != NULL) {
+    sys_untimeout(sntp_request, NULL);
+    udp_remove(sntp_pcb);
+    sntp_pcb = NULL;
+  }
+}
+
+/**
+ * Get enabled state.
+ */
+u8_t sntp_enabled(void)
+{
+  return (sntp_pcb != NULL)? 1 : 0;
+}
+
+/**
+ * Sets the operating mode.
+ * @param operating_mode one of the available operating modes
+ */
+void
+sntp_setoperatingmode(u8_t operating_mode)
+{
+  LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY);
+  LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL);
+  sntp_opmode = operating_mode;
+}
+
+/**
+ * Gets the operating mode.
+ */
+u8_t
+sntp_getoperatingmode(void)
+{
+  return sntp_opmode;
+}
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+/**
+ * Config SNTP server handling by IP address, name, or DHCP; clear table
+ * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp
+ */
+void
+sntp_servermode_dhcp(int set_servers_from_dhcp)
+{
+  u8_t new_mode = set_servers_from_dhcp ? 1 : 0;
+  if (sntp_set_servers_from_dhcp != new_mode) {
+    sntp_set_servers_from_dhcp = new_mode;
+  }
+}
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+
+/**
+ * Initialize one of the NTP servers by IP address
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver IP address of the NTP server to set
+ */
+void
+sntp_setserver(u8_t idx, const ip_addr_t *server)
+{
+  if (idx < SNTP_MAX_SERVERS) {
+    if (server != NULL) {
+      sntp_servers[idx].addr = (*server);
+    } else {
+      ip_addr_set_zero(&sntp_servers[idx].addr);
+    }
+#if SNTP_SERVER_DNS
+    sntp_servers[idx].name = NULL;
+#endif
+  }
+}
+
+#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP
+/**
+ * Initialize one of the NTP servers by IP address, required by DHCP
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver IP address of the NTP server to set
+ */
+void
+dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server)
+{
+  LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n",
+    (sntp_set_servers_from_dhcp ? "Got" : "Rejected"),
+    ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));
+  if (sntp_set_servers_from_dhcp && num) {
+    u8_t i;
+    for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {
+      ip_addr_t addr;
+      ip_addr_copy_from_ip4(addr, server[i]);
+      sntp_setserver(i, &addr);
+    }
+    for (i = num; i < SNTP_MAX_SERVERS; i++) {
+      sntp_setserver(i, NULL);
+    }
+  }
+}
+#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */
+
+/**
+ * Obtain one of the currently configured by IP address (or DHCP) NTP servers
+ *
+ * @param numdns the index of the NTP server
+ * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP
+ *         server has not been configured by address (or at all).
+ */
+ip_addr_t
+sntp_getserver(u8_t idx)
+{
+  if (idx < SNTP_MAX_SERVERS) {
+    return sntp_servers[idx].addr;
+  }
+  return *IP_ADDR_ANY;
+}
+
+#if SNTP_SERVER_DNS
+/**
+ * Initialize one of the NTP servers by name
+ *
+ * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS
+ * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time
+ */
+void
+sntp_setservername(u8_t idx, char *server)
+{
+  if (idx < SNTP_MAX_SERVERS) {
+    sntp_servers[idx].name = server;
+  }
+}
+
+/**
+ * Obtain one of the currently configured by name NTP servers.
+ *
+ * @param numdns the index of the NTP server
+ * @return IP address of the indexed NTP server or NULL if the NTP
+ *         server has not been configured by name (or at all)
+ */
+char *
+sntp_getservername(u8_t idx)
+{
+  if (idx < SNTP_MAX_SERVERS) {
+    return sntp_servers[idx].name;
+  }
+  return NULL;
+}
+#endif /* SNTP_SERVER_DNS */
+
+#endif /* LWIP_UDP */
+
diff --git a/components/lwip/apps/sntp/sntp_time.c b/components/lwip/apps/sntp/sntp_time.c
new file mode 100644 (file)
index 0000000..8cde12f
--- /dev/null
@@ -0,0 +1,308 @@
+#include <string.h>
+#include "apps/sntp_time.h"
+
+s8_t sntp_time_timezone = 8;
+u32_t sntp_time_realtime = 0;
+
+int sntp_time_month;
+int sntp_time_year;
+char sntp_time_result[100];
+sntp_tm_type sntp_time_rule[2];
+sntp_tm sntp_time_result_buf;
+
+static const int sntp_time_mon_lengths[2][12] = {
+  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+} ;
+
+static const int sntp_time_year_lengths[2] = {
+  365,
+  366
+};
+
+sntp_tm *sntp_mktm_r(const sntp_time_t *tim_p, sntp_tm *res, int is_gmtime)
+{
+  long days, rem;
+  sntp_time_t lcltime;
+  int i;
+  int y;
+  int yleap;
+  const int *ip;
+
+  /* base decision about std/dst time on current time */
+  lcltime = *tim_p;
+
+  days = ((long)lcltime) / SECSPERDAY;
+  rem = ((long)lcltime) % SECSPERDAY;
+  while (rem < 0)
+    {
+      rem += SECSPERDAY;
+      --days;
+    }
+  while (rem >= SECSPERDAY)
+    {
+      rem -= SECSPERDAY;
+      ++days;
+    }
+
+  /* compute hour, min, and sec */
+  res->tm_hour = (int) (rem / SECSPERHOUR);
+  rem %= SECSPERHOUR;
+  res->tm_min = (int) (rem / SECSPERMIN);
+  res->tm_sec = (int) (rem % SECSPERMIN);
+
+  /* compute day of week */
+  if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
+    res->tm_wday += DAYSPERWEEK;
+
+  /* compute year & day of year */
+  y = EPOCH_YEAR;
+  if (days >= 0)
+    {
+      for (;;)
+       {
+         yleap = isleap(y);
+         if (days < sntp_time_year_lengths[yleap])
+           break;
+         y++;
+         days -= sntp_time_year_lengths[yleap];
+       }
+    }
+  else
+    {
+      do
+       {
+         --y;
+         yleap = isleap(y);
+         days += sntp_time_year_lengths[yleap];
+       } while (days < 0);
+    }
+
+  res->tm_year = y - YEAR_BASE;
+  res->tm_yday = days;
+  ip = sntp_time_mon_lengths[yleap];
+  for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
+    days -= ip[res->tm_mon];
+  res->tm_mday = days + 1;
+
+  if (!is_gmtime)
+    {
+      int offset;
+      int hours, mins, secs;
+
+         res->tm_isdst = 0;
+
+      offset = (res->tm_isdst == 1 ? sntp_time_rule[1].offset : sntp_time_rule[0].offset);
+
+      hours = offset / SECSPERHOUR;
+      offset = offset % SECSPERHOUR;
+
+      mins = offset / SECSPERMIN;
+      secs = offset % SECSPERMIN;
+
+      res->tm_sec -= secs;
+      res->tm_min -= mins;
+      res->tm_hour -= hours;
+
+      if (res->tm_sec >= SECSPERMIN)
+       {
+         res->tm_min += 1;
+         res->tm_sec -= SECSPERMIN;
+       }
+      else if (res->tm_sec < 0)
+       {
+         res->tm_min -= 1;
+         res->tm_sec += SECSPERMIN;
+       }
+      if (res->tm_min >= MINSPERHOUR)
+       {
+         res->tm_hour += 1;
+         res->tm_min -= MINSPERHOUR;
+       }
+      else if (res->tm_min < 0)
+       {
+         res->tm_hour -= 1;
+         res->tm_min += MINSPERHOUR;
+       }
+      if (res->tm_hour >= HOURSPERDAY)
+       {
+         ++res->tm_yday;
+         ++res->tm_wday;
+         if (res->tm_wday > 6)
+           res->tm_wday = 0;
+         ++res->tm_mday;
+         res->tm_hour -= HOURSPERDAY;
+         if (res->tm_mday > ip[res->tm_mon])
+           {
+             res->tm_mday -= ip[res->tm_mon];
+             res->tm_mon += 1;
+             if (res->tm_mon == 12)
+               {
+                 res->tm_mon = 0;
+                 res->tm_year += 1;
+                 res->tm_yday = 0;
+               }
+           }
+       }
+       else if (res->tm_hour < 0)
+       {
+         res->tm_yday -= 1;
+         res->tm_wday -= 1;
+         if (res->tm_wday < 0)
+           res->tm_wday = 6;
+         res->tm_mday -= 1;
+         res->tm_hour += 24;
+         if (res->tm_mday == 0)
+           {
+             res->tm_mon -= 1;
+             if (res->tm_mon < 0)
+               {
+                 res->tm_mon = 11;
+                 res->tm_year -= 1;
+                 res->tm_yday = 365 + isleap(res->tm_year);
+               }
+             res->tm_mday = ip[res->tm_mon];
+           }
+       }
+    }
+  else
+    res->tm_isdst = 0;
+
+  return (res);
+}
+
+sntp_tm *sntp_localtime_r(const sntp_time_t *tim_p, sntp_tm *res)
+{
+  return sntp_mktm_r (tim_p, res, 0);
+}
+
+sntp_tm *sntp_localtime(const sntp_time_t *tim_p)
+{
+  return sntp_localtime_r (tim_p, &sntp_time_result_buf);
+}
+
+int sntp_limitstime(int year)
+{
+  int days, year_days, years;
+  int i, j;
+
+  if (year < EPOCH_YEAR)
+    return 0;
+
+  sntp_time_year = year;
+
+  years = (year - EPOCH_YEAR);
+
+  year_days = years * 365 +
+    (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
+    (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
+
+  for (i = 0; i < 2; ++i)
+    {
+      if (sntp_time_rule[i].ch == 'J')
+       days = year_days + sntp_time_rule[i].d + (isleap(year) && sntp_time_rule[i].d >= 60);
+      else if (sntp_time_rule[i].ch == 'D')
+       days = year_days + sntp_time_rule[i].d;
+      else
+       {
+         int yleap = isleap(year);
+         int m_day, m_wday, wday_diff;
+         const int *ip = sntp_time_mon_lengths[yleap];
+
+         days = year_days;
+
+         for (j = 1; j < sntp_time_rule[i].m; ++j)
+           days += ip[j-1];
+
+         m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
+
+         wday_diff = sntp_time_rule[i].d - m_wday;
+         if (wday_diff < 0)
+           wday_diff += DAYSPERWEEK;
+         m_day = (sntp_time_rule[i].n - 1) * DAYSPERWEEK + wday_diff;
+
+         while (m_day >= ip[j-1])
+           m_day -= DAYSPERWEEK;
+
+         days += m_day;
+       }
+
+      /* store the change-over time in GMT form by adding offset */
+      sntp_time_rule[i].change = days * SECSPERDAY + sntp_time_rule[i].s + sntp_time_rule[i].offset;
+    }
+
+  sntp_time_month = (sntp_time_rule[0].change < sntp_time_rule[1].change);
+
+  return 1;
+}
+
+char *sntp_asctime_r(sntp_tm *tim_p ,char *result)
+{
+  static const char day_name[7][4] = {
+       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+  };
+  static const char mon_name[12][4] = {
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+  };
+  sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n",
+          day_name[tim_p->tm_wday],
+          mon_name[tim_p->tm_mon],
+          tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min,
+          tim_p->tm_sec, 1900 + tim_p->tm_year);
+  return result;
+}
+char *sntp_asctime(sntp_tm *tim_p)
+{
+    return sntp_asctime_r (tim_p, sntp_time_result);
+}
+
+u32_t sntp_get_current_timestamp(void)
+{
+       if(sntp_time_realtime == 0){
+               printf("please start sntp first !\n");
+               return 0;
+       } else {
+               return sntp_time_realtime;
+       }
+}
+
+char* sntp_get_real_time(sntp_time_t t)
+{
+       return sntp_asctime(sntp_localtime (&t));
+}
+
+/**
+ * SNTP get sntp_time_timezone default GMT + 8
+ */
+s8_t sntp_get_timezone(void)
+{
+       return sntp_time_timezone;
+}
+
+/**
+ * SNTP set sntp_time_timezone default GMT + 8
+ */
+bool sntp_set_timezone(s8_t timezone)
+{
+       if(timezone >= -11 && timezone <= 13) {
+               sntp_time_timezone = timezone;
+               return true;
+       } else {
+               return false;
+       }
+
+}
+void sntp_inc_time(void)
+{
+       sntp_time_realtime ++;
+}
+
+void sntp_convert_time(sntp_time_t GMT_Time)
+{
+       sntp_time_t Local_Time = GMT_Time;
+       Local_Time += sntp_time_timezone * 60 * 60;
+       sntp_time_realtime = Local_Time;
+       printf("%s\n",sntp_asctime(sntp_localtime (&Local_Time)));
+}
+
diff --git a/components/lwip/include/lwip/apps/sntp.h b/components/lwip/include/lwip/apps/sntp.h
new file mode 100644 (file)
index 0000000..bd20968
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007-2009 Fr�d�ric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Fr�d�ric Bernon, Simon Goldschmidt
+ *
+ */
+#ifndef LWIP_HDR_APPS_SNTP_H
+#define LWIP_HDR_APPS_SNTP_H
+
+#include "apps/sntp_opts.h"
+#include "apps/sntp_time.h"
+#include "lwip/ip_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SNTP operating modes: default is to poll using unicast.
+   The mode has to be set before calling sntp_init(). */
+#define SNTP_OPMODE_POLL            0
+#define SNTP_OPMODE_LISTENONLY      1
+void sntp_setoperatingmode(u8_t operating_mode);
+u8_t sntp_getoperatingmode(void);
+
+void sntp_init(void);
+void sntp_stop(void);
+u8_t sntp_enabled(void);
+
+void sntp_setserver(u8_t idx, const ip_addr_t *addr);
+ip_addr_t sntp_getserver(u8_t idx);
+
+#if SNTP_SERVER_DNS
+void sntp_setservername(u8_t idx, char *server);
+char *sntp_getservername(u8_t idx);
+#endif /* SNTP_SERVER_DNS */
+
+#if SNTP_GET_SERVERS_FROM_DHCP
+void sntp_servermode_dhcp(int set_servers_from_dhcp);
+#else /* SNTP_GET_SERVERS_FROM_DHCP */
+#define sntp_servermode_dhcp(x)
+#endif /* SNTP_GET_SERVERS_FROM_DHCP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_HDR_APPS_SNTP_H */
diff --git a/components/lwip/include/lwip/apps/sntp_opts.h b/components/lwip/include/lwip/apps/sntp_opts.h
new file mode 100644 (file)
index 0000000..448d10b
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2007-2009 Fr�d�ric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Fr�d�ric Bernon, Simon Goldschmidt
+ *
+ */
+#ifndef LWIP_HDR_APPS_SNTP_OPTS_H
+#define LWIP_HDR_APPS_SNTP_OPTS_H
+
+#include "lwip/opt.h"
+
+/** SNTP macro to change system time in seconds
+ * Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds instead of this one
+ * if you need the additional precision.
+ */
+#ifndef SNTP_SET_SYSTEM_TIME
+#define SNTP_SET_SYSTEM_TIME(sec)   LWIP_UNUSED_ARG(sec)
+#endif
+
+/** The maximum number of SNTP servers that can be set */
+#ifndef SNTP_MAX_SERVERS
+#define SNTP_MAX_SERVERS           LWIP_DHCP_MAX_NTP_SERVERS
+#endif
+
+/** Set this to 1 to implement the callback function called by dhcp when
+ * NTP servers are received. */
+#ifndef SNTP_GET_SERVERS_FROM_DHCP
+#define SNTP_GET_SERVERS_FROM_DHCP LWIP_DHCP_GET_NTP_SRV
+#endif
+
+/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */
+#ifndef SNTP_SERVER_DNS
+#define SNTP_SERVER_DNS            1
+#endif
+
+/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1:
+ * #define SNTP_SERVER_ADDRESS "pool.ntp.org"
+ */
+
+/**
+ * SNTP_DEBUG: Enable debugging for SNTP.
+ */
+#ifndef SNTP_DEBUG
+#define SNTP_DEBUG                  LWIP_DBG_OFF
+#endif
+
+/** SNTP server port */
+#ifndef SNTP_PORT
+#define SNTP_PORT                   123
+#endif
+
+/** Set this to 1 to allow config of SNTP server(s) by DNS name */
+#ifndef SNTP_SERVER_DNS
+#define SNTP_SERVER_DNS             0
+#endif
+
+/** Sanity check:
+ * Define this to
+ * - 0 to turn off sanity checks (default; smaller code)
+ * - >= 1 to check address and port of the response packet to ensure the
+ *        response comes from the server we sent the request to.
+ * - >= 2 to check returned Originate Timestamp against Transmit Timestamp
+ *        sent to the server (to ensure response to older request).
+ * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp
+ *        fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast).
+ * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each
+ *        greater than or equal to 0 and less than infinity, where infinity is
+ *        currently a cozy number like one second. This check avoids using a
+ *        server whose synchronization source has expired for a very long time.
+ */
+#ifndef SNTP_CHECK_RESPONSE
+#define SNTP_CHECK_RESPONSE         0
+#endif
+
+/** According to the RFC, this shall be a random delay
+ * between 1 and 5 minutes (in milliseconds) to prevent load peaks.
+ * This can be defined to a random generation function,
+ * which must return the delay in milliseconds as u32_t.
+ * Turned off by default.
+ */
+#ifndef SNTP_STARTUP_DELAY
+#define SNTP_STARTUP_DELAY          0
+#endif
+
+/** If you want the startup delay to be a function, define this
+ * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1.
+ */
+#ifndef SNTP_STARTUP_DELAY_FUNC
+#define SNTP_STARTUP_DELAY_FUNC     SNTP_STARTUP_DELAY
+#endif
+
+/** SNTP receive timeout - in milliseconds
+ * Also used as retry timeout - this shouldn't be too low.
+ * Default is 3 seconds.
+ */
+#ifndef SNTP_RECV_TIMEOUT
+#define SNTP_RECV_TIMEOUT           3000
+#endif
+
+/** SNTP update delay - in milliseconds
+ * Default is 1 hour. Must not be beolw 15 seconds by specification (i.e. 15000)
+ */
+#ifndef SNTP_UPDATE_DELAY
+#define SNTP_UPDATE_DELAY           3600000
+#endif
+
+/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2
+ * to send in request and compare in response.
+ */
+#ifndef SNTP_GET_SYSTEM_TIME
+#define SNTP_GET_SYSTEM_TIME(sec, us)     do { (sec) = 0; (us) = 0; } while(0)
+#endif
+
+/** Default retry timeout (in milliseconds) if the response
+ * received is invalid.
+ * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached.
+ */
+#ifndef SNTP_RETRY_TIMEOUT
+#define SNTP_RETRY_TIMEOUT          SNTP_RECV_TIMEOUT
+#endif
+
+/** Maximum retry timeout (in milliseconds). */
+#ifndef SNTP_RETRY_TIMEOUT_MAX
+#define SNTP_RETRY_TIMEOUT_MAX      (SNTP_RETRY_TIMEOUT * 10)
+#endif
+
+/** Increase retry timeout with every retry sent
+ * Default is on to conform to RFC.
+ */
+#ifndef SNTP_RETRY_TIMEOUT_EXP
+#define SNTP_RETRY_TIMEOUT_EXP      1
+#endif
+
+#endif /* LWIP_HDR_APPS_SNTP_OPTS_H */
diff --git a/components/lwip/include/lwip/apps/sntp_time.h b/components/lwip/include/lwip/apps/sntp_time.h
new file mode 100644 (file)
index 0000000..2d65278
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2007-2009 Fr�d�ric Bernon, Simon Goldschmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Fr�d�ric Bernon, Simon Goldschmidt
+ *
+ */
+#ifndef LWIP_HDR_APPS_SNTP_TIME_H
+#define LWIP_HDR_APPS_SNTP_TIME_H
+
+#include "lwip/opt.h"
+#include "lwip/timers.h"
+
+#define SECSPERMIN     60L
+#define MINSPERHOUR    60L
+#define HOURSPERDAY    24L
+#define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY     (SECSPERHOUR * HOURSPERDAY)
+#define DAYSPERWEEK    7
+#define MONSPERYEAR    12
+
+#define YEAR_BASE      1900
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      4
+#define EPOCH_YEARS_SINCE_LEAP 2
+#define EPOCH_YEARS_SINCE_CENTURY 70
+#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+typedef long sntp_time_t;
+
+typedef struct{
+  int  tm_sec;
+  int  tm_min;
+  int  tm_hour;
+  int  tm_mday;
+  int  tm_mon;
+  int  tm_year;
+  int  tm_wday;
+  int  tm_yday;
+  int  tm_isdst;
+}sntp_tm;
+
+typedef struct{
+  char ch;
+  int m;
+  int n;
+  int d;
+  int s;
+  sntp_time_t change;
+  int offset;
+}sntp_tm_type;
+
+void sntp_convert_time(sntp_time_t GMT_Time);
+
+#endif
+