167 lines
5.2 KiB
C++
167 lines
5.2 KiB
C++
#include "time_manager.h"
|
|
#include <ESP8266TimerInterrupt.h> // https://github.com/khoih-prog/ESP8266TimerInterrupt
|
|
#include "wordclock_constants.h"
|
|
#include "time.h"
|
|
|
|
extern UDPLogger logger;
|
|
extern ESP8266Timer ITimer; // ESP8266 Timer
|
|
extern void IRAM_ATTR TimerHandler(); // ISR function
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
// Class
|
|
// ----------------------------------------------------------------------------------
|
|
TimeManager::TimeManager(const char *tz,
|
|
const char *ntp_server,
|
|
uint32 ntp_update_period_s,
|
|
uint32 ntp_retry_delay_us,
|
|
uint32 ntp_max_offline_time_s,
|
|
UDPLogger *logger)
|
|
{
|
|
_tz = tz;
|
|
_ntp_server = ntp_server;
|
|
_ntp_max_offline_time_s = ntp_max_offline_time_s;
|
|
_ntp_retry_delay_us = ntp_retry_delay_us;
|
|
_ntp_update_period_s = ntp_update_period_s;
|
|
_logger = logger;
|
|
}
|
|
|
|
struct tm TimeManager::time_info(void)
|
|
{
|
|
localtime_r(&_time_now_local, &_time_info); // convert time
|
|
return _time_info;
|
|
}
|
|
|
|
bool TimeManager::ntp_sync_successful(void) const
|
|
{
|
|
return (_time_now_ntp > 0);
|
|
}
|
|
|
|
/**
|
|
* @brief NTP time update, should be called in loop().
|
|
*
|
|
* @retval true if last update was successful
|
|
*/
|
|
bool 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))))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (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_sync_timestamp_us = system_get_time(); // NTP update start time
|
|
|
|
do
|
|
{
|
|
time(&_time_now_ntp); // get time from server and save it into _time_now_ntp
|
|
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)));
|
|
|
|
ntp_update_successful = (time_info.tm_year <= (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR)) ? false : true; // sanity check
|
|
|
|
if (ntp_update_successful == true)
|
|
{
|
|
_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
|
|
|
|
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
|
|
{
|
|
_logger->log_string(String("Difference between local and NTP time was more than 10 seconds!\n"));
|
|
_logger->log_string("Local time was: " + String(_time_now_local) + ", NTP time is: " + String(_time_now_ntp) + "\n");
|
|
}
|
|
|
|
_time_now_local = _time_now_ntp; // sync local time with NTP time
|
|
|
|
if (init) // only set up the timer once after NTP update was successful
|
|
{
|
|
set_up_timer_isr();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger.log_string("NTP-Update was not successful. Retrying in " + String(_ntp_retry_delay_us / 1000) + "ms.\n");
|
|
}
|
|
|
|
return ntp_update_successful;
|
|
}
|
|
|
|
bool TimeManager::ntp_update_failed_prolonged(void) const
|
|
{
|
|
return _time_now_local >= (_time_now_ntp + (time_t)_ntp_max_offline_time_s);
|
|
}
|
|
|
|
int TimeManager::tm_min(void)
|
|
{
|
|
localtime_r(&_time_now_local, &_time_info); // convert time
|
|
return _time_info.tm_min;
|
|
}
|
|
|
|
int TimeManager::tm_hour(void)
|
|
{
|
|
localtime_r(&_time_now_local, &_time_info); // convert time
|
|
return _time_info.tm_hour;
|
|
}
|
|
|
|
int TimeManager::tm_year(void)
|
|
{
|
|
localtime_r(&_time_now_local, &_time_info); // convert time
|
|
return _time_info.tm_year;
|
|
}
|
|
|
|
bool TimeManager::tm_isdst(void)
|
|
{
|
|
localtime_r(&_time_now_local, &_time_info); // convert time
|
|
return _time_info.tm_isdst > 0;
|
|
}
|
|
|
|
// TODO
|
|
void TimeManager::set_up_timer_isr(void) const
|
|
{
|
|
// set up timer interrupt after NTP update is done
|
|
if (ntp_sync_successful())
|
|
{
|
|
(void)ITimer.attachInterruptInterval(PERIOD_CLOCK_UPDATE_US, TimerHandler);
|
|
}
|
|
else
|
|
{
|
|
logger.log_string("WARNING: Timer interrupt was not attached!");
|
|
}
|
|
}
|
|
|
|
void TimeManager::set_up_ntp(void) const
|
|
{
|
|
if ((_tz != nullptr) && (_ntp_server != nullptr))
|
|
{
|
|
// set up NTP server and timezone at init
|
|
configTime(_tz, _ntp_server);
|
|
logger.log_string(String("NTP server was initialized!"));
|
|
}
|
|
else
|
|
{
|
|
logger.log_string(String("Timezone and/or NTP-Server were not given!"));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Log time_info as string.
|
|
*
|
|
* @param local_time
|
|
*/
|
|
void TimeManager::log_time(struct tm time_info) const
|
|
{
|
|
char strftime_buf[64]; // Time string buffer
|
|
strftime(strftime_buf, sizeof(strftime_buf), "%c", &time_info);
|
|
logger.log_string(String(strftime_buf));
|
|
}
|