diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 01931549c5..d84cfa3c57 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -16,6 +16,9 @@ static uint8_t SNTPQueryData[48] = { // NTP query frequency - 5 minutes #define NTP_QUERY_FREQUENCY (5 * 60) +// NTP sample window (should be odd) +#define NTP_SAMPLE_WINDOW 9 + // NTP timestamp constant #define NTP_UNIX_OFFSET 0x83AA7E80 @@ -138,16 +141,26 @@ void SNTPClient::processReply() timev -= now; timev -= NTP_UNIX_OFFSET; - if ((timev == -1) || (timev == 1)) // small corrections likely do more harm than good - timev = 0; - - // FIXME: We really should use the median of all recent valid offsets - if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) - mOffset = timev; - else - mOffset = ((mOffset * 7) + timev) / 8; + // add offset to list, replacing oldest one if appropriate + mOffsetList.push_back(timev); + if (mOffsetList.size() >= NTP_SAMPLE_WINDOW) + mOffsetList.pop_front(); mLastOffsetUpdate = now; + // select median time + std::list offsetList = mOffsetList; + offsetList.sort(); + int j = offsetList.size(); + std::list::iterator it = offsetList.begin(); + for (int i = 0; i < (j / 2); ++i) + ++it; + mOffset = *it; + if ((j % 2) == 0) + mOffset = (mOffset + (*--it)) / 2; + + if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good + mOffset = 0; + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } diff --git a/src/SNTPClient.h b/src/SNTPClient.h index 06f54ad0ce..ea7b0e7c8a 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -33,8 +34,10 @@ protected: boost::asio::ip::udp::resolver mResolver; std::vector< std::pair > mServers; + int mOffset; time_t mLastOffsetUpdate; + std::list mOffsetList; std::vector mReceiveBuffer; boost::asio::ip::udp::endpoint mReceiveEndpoint;