From 5a51707452bab55b30e363f8057c99897c8e333f Mon Sep 17 00:00:00 2001 From: Markus Ransberger Date: Thu, 4 Apr 2024 01:45:11 +0200 Subject: [PATCH] Add NTP update state. Refactoring. --- include/time_manager.h | 44 ++++++++++++++--------- include/wordclock_constants.h | 2 +- src/connectivity/time_manager.cpp | 58 ++++++++++++++++++++++++------- src/wordclock_esp8266.cpp | 9 +++-- 4 files changed, 81 insertions(+), 32 deletions(-) diff --git a/include/time_manager.h b/include/time_manager.h index 0d65bbb..0544300 100644 --- a/include/time_manager.h +++ b/include/time_manager.h @@ -5,20 +5,32 @@ #include #include "udp_logger.h" -#define NTP_MAX_UPDATE_TIME_US (500 * 1000) // 500ms max update time +typedef enum +{ + NTP_UPDATE_FAILED = 0, + NTP_UPDATE_OK = 1, + NTP_UPDATE_PENDING = 2, + NTP_UPDATE_RETRY_DELAY = 3, + NTP_UPDATE_TOO_EARLY = 4, +} ntp_update_state; class TimeManager { +#define NTP_MAX_UPDATE_TIME_US (500 * 1000) // 500ms max update time + public: - struct tm time_info(void); bool ntp_sync_successful(void) const; // was there a NTP sync once? - bool ntp_time_update(bool init = false); + ntp_update_state ntp_time_update(bool init = false); bool ntp_update_failed_prolonged(void) const; // indicates if maximum time since last NTP update was too long - void log_time(struct tm time_info) const; // log local_time + struct tm time_info(void); void increment_time_now_local(void); + void log_time() const; // log _time_info + void log_time(struct tm time_info) const; // log argument time_info int tm_min(void); int tm_hour(void); + int tm_day(void); + int tm_mon(void); int tm_year(void); bool tm_isdst(void); // true if summertime @@ -30,18 +42,18 @@ public: UDPLogger *logger); private: - void set_up_ntp(void) const; // set up NTP server - void set_up_timer_isr(void) const; // set up timer interrupt - const char *_tz; // timezone - const char *_ntp_server; // used ntp server - UDPLogger *_logger; // logger instance - struct tm _time_info; // structure tm holds time information - time_t _time_now_local = 0; // local timer value, updated by timer interrupt and synced by NTP when needed - time_t _time_now_ntp = 0; // NTP timer value, seconds since Epoch (1970) - UTC, only synced by NTP request. - uint32 _ntp_max_offline_time_s; // maximum time in seconds which is considered ok since last NTP update - uint32 _ntp_update_period_s; // NTP request update period in seconds - uint32 _ntp_retry_delay_us; // minimum retry delay in us between two NTP requests - uint32 _ntp_sync_timestamp_us = 0; // timestamp of last successful ntp update + void set_up_ntp(void) const; // set up NTP server + void set_up_timer_isr(void) const; // set up timer interrupt + const char *_tz; // timezone + const char *_ntp_server; // used ntp server + UDPLogger *_logger; // logger instance + struct tm _time_info = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // structure tm holds time information + time_t _time_now_local = 0; // local timer value, updated by timer interrupt and synced by NTP when needed + time_t _time_now_ntp = 0; // NTP timer value, seconds since Epoch (1970) - UTC, only synced by NTP request. + uint32 _ntp_max_offline_time_s; // maximum time in seconds which is considered ok since last NTP update + uint32 _ntp_update_period_s; // NTP request update period in seconds + uint32 _ntp_retry_delay_us; // minimum retry delay in us between two NTP requests + uint32 _ntp_sync_timestamp_us = 0; // timestamp of last successful ntp update }; inline void TimeManager::increment_time_now_local(void) diff --git a/include/wordclock_constants.h b/include/wordclock_constants.h index f6c918c..7b56bb2 100644 --- a/include/wordclock_constants.h +++ b/include/wordclock_constants.h @@ -71,7 +71,7 @@ // NTP macros #define BUILD_YEAR (__DATE__ + 7) // Will expand to current year at compile time as string. #define NTP_MININUM_RX_YEAR (atoi(BUILD_YEAR) - 1) // Will expand to current year minus one at compile time. -#define NTP_MININUM_YEAR (1900) // NTP minimum year is 1900 +#define NTP_START_YEAR (1900) // NTP minimum year is 1900 #define NTP_UPDATE_PERIOD_S (12 * 3600) // 12h period between updates #define NTP_RETRY_DELAY_US (10 * 1000 * 1000) // 10s retry delay time between failed NTP requests #define NTP_MAX_OFFLINE_TIME_S (7 * 24 * 3600) // Watchdog value, maxmimum offline time before a restart is triggered diff --git a/src/connectivity/time_manager.cpp b/src/connectivity/time_manager.cpp index 0447583..417411e 100644 --- a/src/connectivity/time_manager.cpp +++ b/src/connectivity/time_manager.cpp @@ -41,12 +41,17 @@ bool TimeManager::ntp_sync_successful(void) const * * @retval true if last update was successful */ -bool TimeManager::ntp_time_update(bool init) +ntp_update_state TimeManager::ntp_time_update(bool init) { // Check if minimum update delay has elapsed - if (!init && (((system_get_time() - _ntp_sync_timestamp_us) <= _ntp_retry_delay_us) || ((system_get_time() - _ntp_sync_timestamp_us) <= (_ntp_update_period_s * 1000000)))) + if (!init && ((system_get_time() - _ntp_sync_timestamp_us) <= _ntp_retry_delay_us)) { - return false; + return NTP_UPDATE_RETRY_DELAY; // could be replaced with appropriate enum + } + + if (!init && ((system_get_time() - _ntp_sync_timestamp_us) <= (_ntp_update_period_s * 1000000))) + { + return NTP_UPDATE_TOO_EARLY; // could be replaced with appropriate enum } if (init) @@ -54,8 +59,8 @@ bool TimeManager::ntp_time_update(bool init) set_up_ntp(); // set up NTP server once } - bool ntp_update_successful = false; // NTP time update - struct tm time_info; // local NTP time info + ntp_update_state ntp_update_state = NTP_UPDATE_PENDING; // NTP time update + struct tm time_info; // local NTP time info _ntp_sync_timestamp_us = system_get_time(); // NTP update start time @@ -65,15 +70,15 @@ bool TimeManager::ntp_time_update(bool init) localtime_r(&_time_now_ntp, &time_info); // convert time yield(); // since this loop could take up to NTP_MAX_UPDATE_TIME_US - } while (((system_get_time() - _ntp_sync_timestamp_us) <= NTP_MAX_UPDATE_TIME_US) && (time_info.tm_year < (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR))); + } while (((system_get_time() - _ntp_sync_timestamp_us) <= NTP_MAX_UPDATE_TIME_US) && (time_info.tm_year < (NTP_MININUM_RX_YEAR - NTP_START_YEAR))); - ntp_update_successful = (time_info.tm_year <= (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR)) ? false : true; // sanity check + ntp_update_state = (time_info.tm_year <= (NTP_MININUM_RX_YEAR - NTP_START_YEAR)) ? NTP_UPDATE_FAILED : NTP_UPDATE_OK; // sanity check - if (ntp_update_successful == true) + if (ntp_update_state == NTP_UPDATE_OK) { _ntp_sync_timestamp_us = system_get_time(); // save NTP update timestamp _time_info = time_info; // take over time_info to member variable - log_time(_time_info); // log current time + log_time(); // log current time if (!init && (abs(_time_now_ntp - _time_now_local) > 10)) // in the case that the local time drifted more than 10s in _ntp_update_period_s { @@ -93,7 +98,7 @@ bool TimeManager::ntp_time_update(bool init) logger.log_string("NTP-Update was not successful. Retrying in " + String(_ntp_retry_delay_us / 1000) + "ms.\n"); } - return ntp_update_successful; + return ntp_update_state; } bool TimeManager::ntp_update_failed_prolonged(void) const @@ -113,10 +118,22 @@ int TimeManager::tm_hour(void) return _time_info.tm_hour; } +int TimeManager::tm_day(void) +{ + localtime_r(&_time_now_local, &_time_info); // convert time + return _time_info.tm_mday + 1; // add 1 to get actual day +} + int TimeManager::tm_year(void) { localtime_r(&_time_now_local, &_time_info); // convert time - return _time_info.tm_year; + return _time_info.tm_year + NTP_START_YEAR; // add start year to get actual year +} + +int TimeManager::tm_mon(void) +{ + localtime_r(&_time_now_local, &_time_info); // convert time + return _time_info.tm_mon + 1; // add 1 to get actual month } bool TimeManager::tm_isdst(void) @@ -125,7 +142,10 @@ bool TimeManager::tm_isdst(void) return _time_info.tm_isdst > 0; } -// TODO +/** + * @brief Sets up the timer ISR + * + */ void TimeManager::set_up_timer_isr(void) const { // set up timer interrupt after NTP update is done @@ -139,6 +159,10 @@ void TimeManager::set_up_timer_isr(void) const } } +/** + * @brief Sets up the NTP server config + * + */ void TimeManager::set_up_ntp(void) const { if ((_tz != nullptr) && (_ntp_server != nullptr)) @@ -153,6 +177,16 @@ void TimeManager::set_up_ntp(void) const } } +/** + * @brief Log time_info as string. + * + * @param local_time + */ +void TimeManager::log_time() const +{ + log_time(_time_info); +} + /** * @brief Log time_info as string. * diff --git a/src/wordclock_esp8266.cpp b/src/wordclock_esp8266.cpp index 78ab92a..3c898ba 100644 --- a/src/wordclock_esp8266.cpp +++ b/src/wordclock_esp8266.cpp @@ -195,7 +195,7 @@ void setup() } // get initial time - if (tm_mgr.ntp_time_update(true)) + if (tm_mgr.ntp_time_update(true) == NTP_UPDATE_OK) { // show the current time for short time in words String timeMessage = time_to_string(tm_mgr.tm_hour(), tm_mgr.tm_min()); @@ -251,6 +251,9 @@ void loop() if ((current_time_us - last_heartbeat_us) >= PERIOD_HEARTBEAT_US) { send_heartbeat(); // send heartbeat update + + tm_mgr.log_time(); // TODO rm + last_heartbeat_us = system_get_time(); delay(10); } @@ -282,11 +285,11 @@ void loop() { if (tm_mgr.ntp_sync_successful() == true) // regular case { - tm_mgr.ntp_time_update(); // NTP time update + (void)tm_mgr.ntp_time_update(); // NTP time update } else // if there was never a NTP time update before (set up failed) { - tm_mgr.ntp_time_update(true); // NTP time update with init! + (void)tm_mgr.ntp_time_update(true); // NTP time update with init! } if (tm_mgr.ntp_update_failed_prolonged() == true)