Files
DD3-LoRa-Bridge-MultiSender/src/time_manager.cpp

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;
}