mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-04-16 08:43:17 +00:00
SNTP: Streamline timestamp handling
Generalize the NTP timestamp conversion arithmetic, and provide hooks for using native NTP timestamps when setting or getting the system clock time. Convert microseconds to a fraction as needed when getting the system time.
This commit is contained in:
parent
9323ad3211
commit
2fa9cd8530
@ -76,17 +76,6 @@
|
|||||||
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
#error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!"
|
||||||
#endif
|
#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 */
|
/* the various debug levels for this file */
|
||||||
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
#define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE)
|
||||||
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
#define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE)
|
||||||
@ -121,18 +110,55 @@
|
|||||||
#define SNTP_OFFSET_RECEIVE_TIME 32
|
#define SNTP_OFFSET_RECEIVE_TIME 32
|
||||||
#define SNTP_OFFSET_TRANSMIT_TIME 40
|
#define SNTP_OFFSET_TRANSMIT_TIME 40
|
||||||
|
|
||||||
/* number of seconds between 1900 and 1970 (MSB=1)*/
|
/* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */
|
||||||
#define DIFF_SEC_1900_1970 (2208988800UL)
|
#define DIFF_SEC_1970_2036 ((u32_t)2085978496L)
|
||||||
/* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */
|
|
||||||
#define DIFF_SEC_1970_2036 (2085978496UL)
|
/** Convert NTP timestamp fraction to microseconds.
|
||||||
|
*/
|
||||||
|
#ifndef SNTP_FRAC_TO_US
|
||||||
|
# if LWIP_HAVE_INT64
|
||||||
|
# define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32))
|
||||||
|
# else
|
||||||
|
# define SNTP_FRAC_TO_US(f) ((u32_t)(f) / 4295)
|
||||||
|
# endif
|
||||||
|
#endif /* !SNTP_FRAC_TO_US */
|
||||||
|
|
||||||
|
/* Configure behaviour depending on native, microsecond or second precision.
|
||||||
|
* Treat NTP timestamps as signed two's-complement integers. This way,
|
||||||
|
* timestamps that have the MSB set simply become negative offsets from
|
||||||
|
* the epoch (Feb 7, 2036 06:28:16 UTC). Representable dates range from
|
||||||
|
* 1968 to 2104.
|
||||||
|
*/
|
||||||
|
#ifndef SNTP_SET_SYSTEM_TIME_NTP
|
||||||
|
# ifdef SNTP_SET_SYSTEM_TIME_US
|
||||||
|
# define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
||||||
|
SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f))
|
||||||
|
# else
|
||||||
|
# define SNTP_SET_SYSTEM_TIME_NTP(s, f) \
|
||||||
|
SNTP_SET_SYSTEM_TIME((u32_t)((s) + DIFF_SEC_1970_2036))
|
||||||
|
# endif
|
||||||
|
#endif /* !SNTP_SET_SYSTEM_TIME_NTP */
|
||||||
|
|
||||||
|
/* Get the system time either natively as NTP timestamp or convert from
|
||||||
|
* Unix time in seconds and microseconds. Take care to avoid overflow if the
|
||||||
|
* microsecond value is at the maximum of 999999. Also add 0.5 us fudge to
|
||||||
|
* avoid special values like 0, and to mask round-off errors that would
|
||||||
|
* otherwise break round-trip conversion identity.
|
||||||
|
*/
|
||||||
|
#ifndef SNTP_GET_SYSTEM_TIME_NTP
|
||||||
|
# define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \
|
||||||
|
u32_t sec_, usec_; \
|
||||||
|
SNTP_GET_SYSTEM_TIME(sec_, usec_); \
|
||||||
|
(s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \
|
||||||
|
(f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \
|
||||||
|
} while (0)
|
||||||
|
#endif /* !SNTP_GET_SYSTEM_TIME_NTP */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SNTP packet format (without optional fields)
|
* SNTP packet format (without optional fields)
|
||||||
* Timestamps are coded as 64 bits:
|
* Timestamps are coded as 64 bits:
|
||||||
* - 32 bits seconds since Jan 01, 1970, 00:00
|
* - signed 32 bits seconds since Feb 07, 2036, 06:28:16 UTC (epoch 1)
|
||||||
* - 32 bits seconds fraction (0-padded)
|
* - unsigned 32 bits seconds fraction (2^32 = 1 second)
|
||||||
* 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
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
# include "arch/bpstruct.h"
|
# include "arch/bpstruct.h"
|
||||||
@ -203,34 +229,32 @@ static ip_addr_t sntp_last_server_address;
|
|||||||
static u32_t sntp_last_timestamp_sent[2];
|
static u32_t sntp_last_timestamp_sent[2];
|
||||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||||
|
|
||||||
|
#ifndef sntp_format_time
|
||||||
|
/* Debug print helper. */
|
||||||
|
static const char *
|
||||||
|
sntp_format_time(s32_t sec)
|
||||||
|
{
|
||||||
|
time_t ut;
|
||||||
|
ut = (u32_t)((u32_t)sec + DIFF_SEC_1970_2036);
|
||||||
|
return ctime(&ut);
|
||||||
|
}
|
||||||
|
#endif /* !sntp_format_time */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SNTP processing of received timestamp
|
* SNTP processing of received timestamp
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sntp_process(u32_t *receive_timestamp)
|
sntp_process(u32_t *receive_timestamp)
|
||||||
{
|
{
|
||||||
/* convert SNTP time (1900-based) to unix GMT time (1970-based)
|
s32_t sec;
|
||||||
* if MSB is 0, SNTP time is 2036-based!
|
u32_t frac;
|
||||||
*/
|
|
||||||
u32_t rx_secs = lwip_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
|
sec = lwip_ntohl(receive_timestamp[0]);
|
||||||
u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295;
|
frac = lwip_ntohl(receive_timestamp[1]);
|
||||||
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 */
|
SNTP_SET_SYSTEM_TIME_NTP(sec, frac);
|
||||||
|
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %" U32_F " us\n",
|
||||||
/* change system time and/or the update the RTC clock */
|
sntp_format_time(sec), SNTP_FRAC_TO_US(frac)));
|
||||||
SNTP_SET_SYSTEM_TIME(t);
|
|
||||||
/* display local time from GMT time */
|
|
||||||
LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim)));
|
|
||||||
#endif /* SNTP_CALC_TIME_US */
|
|
||||||
LWIP_UNUSED_ARG(tim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,14 +268,16 @@ sntp_initialize_request(struct sntp_msg *req)
|
|||||||
|
|
||||||
#if SNTP_CHECK_RESPONSE >= 2
|
#if SNTP_CHECK_RESPONSE >= 2
|
||||||
{
|
{
|
||||||
u32_t sntp_time_sec, sntp_time_us;
|
u32_t sec, frac;
|
||||||
/* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */
|
/* Get the transmit timestamp */
|
||||||
SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);
|
SNTP_GET_SYSTEM_TIME_NTP(sec, frac);
|
||||||
sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970);
|
sec = lwip_htonl(sec);
|
||||||
req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];
|
frac = lwip_htonl(frac);
|
||||||
/* we send/save us instead of fraction to be faster... */
|
|
||||||
sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us);
|
sntp_last_timestamp_sent[0] = sec;
|
||||||
req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];
|
sntp_last_timestamp_sent[1] = frac;
|
||||||
|
req->transmit_timestamp[0] = sec;
|
||||||
|
req->transmit_timestamp[1] = frac;
|
||||||
}
|
}
|
||||||
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
#endif /* SNTP_CHECK_RESPONSE >= 2 */
|
||||||
}
|
}
|
||||||
@ -336,7 +362,7 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr,
|
|||||||
{
|
{
|
||||||
u8_t mode;
|
u8_t mode;
|
||||||
u8_t stratum;
|
u8_t stratum;
|
||||||
u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];
|
u32_t receive_timestamp[2];
|
||||||
err_t err;
|
err_t err;
|
||||||
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
LWIP_UNUSED_ARG(arg);
|
||||||
@ -383,7 +409,7 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr,
|
|||||||
{
|
{
|
||||||
/* correct answer */
|
/* correct answer */
|
||||||
err = ERR_OK;
|
err = ERR_OK;
|
||||||
pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME);
|
pbuf_copy_partial(p, &receive_timestamp, 8, SNTP_OFFSET_TRANSMIT_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -46,8 +46,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/** SNTP macro to change system time in seconds
|
/** 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
|
* Define SNTP_SET_SYSTEM_TIME_US(sec, us) to set the time in microseconds
|
||||||
* if you need the additional precision.
|
* instead of this one if you need the additional precision. Alternatively,
|
||||||
|
* define SNTP_SET_SYSTEM_TIME_NTP(sec, frac) in order to work with native
|
||||||
|
* NTP timestamps instead.
|
||||||
*/
|
*/
|
||||||
#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__
|
#if !defined SNTP_SET_SYSTEM_TIME || defined __DOXYGEN__
|
||||||
#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec)
|
#define SNTP_SET_SYSTEM_TIME(sec) LWIP_UNUSED_ARG(sec)
|
||||||
@ -141,6 +143,8 @@
|
|||||||
|
|
||||||
/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2
|
/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2
|
||||||
* to send in request and compare in response.
|
* to send in request and compare in response.
|
||||||
|
* Alternatively, define SNTP_GET_SYSTEM_TIME_NTP(sec, frac) in order to
|
||||||
|
* work with native NTP timestamps instead.
|
||||||
*/
|
*/
|
||||||
#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__
|
#if !defined SNTP_GET_SYSTEM_TIME || defined __DOXYGEN__
|
||||||
#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0)
|
#define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user