125 lines
2.9 KiB
C++
125 lines
2.9 KiB
C++
#include "time_manager.h"
|
|
#include "config.h"
|
|
#include <time.h>
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
#include <esp_sntp.h>
|
|
#endif
|
|
|
|
static bool g_time_synced = false;
|
|
static bool g_clock_plausible = false;
|
|
static bool g_tz_set = false;
|
|
static uint32_t g_last_sync_utc = 0;
|
|
static constexpr uint32_t MIN_PLAUSIBLE_EPOCH_UTC = 1672531200UL; // 2023-01-01 00:00:00 UTC
|
|
|
|
static void note_last_sync(uint32_t epoch) {
|
|
if (epoch == 0) {
|
|
return;
|
|
}
|
|
g_last_sync_utc = epoch;
|
|
}
|
|
|
|
static bool epoch_is_plausible(time_t epoch) {
|
|
return epoch >= static_cast<time_t>(MIN_PLAUSIBLE_EPOCH_UTC);
|
|
}
|
|
|
|
static void mark_synced(uint32_t epoch) {
|
|
if (epoch == 0) {
|
|
return;
|
|
}
|
|
g_time_synced = true;
|
|
g_clock_plausible = true;
|
|
note_last_sync(epoch);
|
|
}
|
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
static void ntp_sync_notification_cb(struct timeval *tv) {
|
|
time_t epoch = tv ? tv->tv_sec : time(nullptr);
|
|
if (!epoch_is_plausible(epoch)) {
|
|
return;
|
|
}
|
|
if (epoch > static_cast<time_t>(UINT32_MAX)) {
|
|
return;
|
|
}
|
|
mark_synced(static_cast<uint32_t>(epoch));
|
|
}
|
|
#endif
|
|
|
|
static void ensure_timezone_set() {
|
|
if (g_tz_set) {
|
|
return;
|
|
}
|
|
setenv("TZ", TIMEZONE_TZ, 1);
|
|
tzset();
|
|
g_tz_set = true;
|
|
}
|
|
|
|
void time_receiver_init(const char *ntp_server_1, const char *ntp_server_2) {
|
|
const char *server1 = (ntp_server_1 && ntp_server_1[0] != '\0') ? ntp_server_1 : "pool.ntp.org";
|
|
const char *server2 = (ntp_server_2 && ntp_server_2[0] != '\0') ? ntp_server_2 : "time.nist.gov";
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
sntp_set_time_sync_notification_cb(ntp_sync_notification_cb);
|
|
#endif
|
|
configTime(0, 0, server1, server2);
|
|
ensure_timezone_set();
|
|
}
|
|
|
|
uint32_t time_get_utc() {
|
|
time_t now = time(nullptr);
|
|
if (!epoch_is_plausible(now)) {
|
|
g_clock_plausible = false;
|
|
return 0;
|
|
}
|
|
g_clock_plausible = true;
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
if (!g_time_synced && sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
|
|
mark_synced(static_cast<uint32_t>(now));
|
|
}
|
|
#endif
|
|
return static_cast<uint32_t>(now);
|
|
}
|
|
|
|
bool time_is_synced() {
|
|
(void)time_get_utc();
|
|
return g_time_synced && g_clock_plausible;
|
|
}
|
|
|
|
void time_set_utc(uint32_t epoch) {
|
|
ensure_timezone_set();
|
|
struct timeval tv;
|
|
tv.tv_sec = epoch;
|
|
tv.tv_usec = 0;
|
|
settimeofday(&tv, nullptr);
|
|
if (epoch_is_plausible(static_cast<time_t>(epoch))) {
|
|
mark_synced(epoch);
|
|
} else {
|
|
g_clock_plausible = false;
|
|
g_time_synced = false;
|
|
}
|
|
}
|
|
|
|
void time_get_local_hhmm(char *out, size_t out_len) {
|
|
if (!time_is_synced()) {
|
|
snprintf(out, out_len, "--:--");
|
|
return;
|
|
}
|
|
time_t now = time(nullptr);
|
|
struct tm timeinfo;
|
|
localtime_r(&now, &timeinfo);
|
|
snprintf(out, out_len, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
|
|
}
|
|
|
|
uint32_t time_get_last_sync_utc() {
|
|
return g_last_sync_utc;
|
|
}
|
|
|
|
uint32_t time_get_last_sync_age_sec() {
|
|
if (!time_is_synced()) {
|
|
return 0;
|
|
}
|
|
if (g_last_sync_utc == 0) {
|
|
return 0;
|
|
}
|
|
uint32_t now = time_get_utc();
|
|
return now > g_last_sync_utc ? now - g_last_sync_utc : 0;
|
|
}
|