Time Sync
Source: src/time_sync.c · 140 lines · 9 functions.
Module entry points
These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.
How to read these diagrams
Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.
These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.
Functions in this file
time_sync_callback() · source line 26
static void time_sync_callback(struct timeval *time_value)
- Execute
(void)time_value; - Execute
status = TIME_SYNC_SYNCHRONIZED; - Execute
save_pending = true; - Execute
ESP_LOGI(TAG, "Time synchronized");
Read original function source
static void time_sync_callback(struct timeval *time_value)
{
(void)time_value;
status = TIME_SYNC_SYNCHRONIZED;
save_pending = true;
ESP_LOGI(TAG, "Time synchronized");
}timeSyncInitialize() · source line 34
bool timeSyncInitialize(void)
Calls into this documentation:
- Execute
bool found = false; - Execute
time_sync_record_t saved = {0}; - Decision
!game_storage_read(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY, &saved, sizeof(saved), &found)True- Exit this function
return false;
FalseContinue after this decision.
- Decision
found && saved.version == TIME_SYNC_RECORD_VERSION && saved.epoch_seconds >= 1704067200LLTrue- Execute
const struct timeval time_value = {.tv_sec = (time_t)saved.epoch_seconds, .tv_usec = 0}; - Decision
settimeofday(&time_value, NULL) == 0True- Execute
ESP_LOGI(TAG, "Restored saved clock time");
FalseContinue after this decision.
FalseContinue after this decision.
- Exit this function
return true;
Read original function source
bool timeSyncInitialize(void)
{
bool found = false;
time_sync_record_t saved = {0};
if (!game_storage_read(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY,
&saved, sizeof(saved), &found)) return false;
if (found && saved.version == TIME_SYNC_RECORD_VERSION && saved.epoch_seconds >= 1704067200LL) {
const struct timeval time_value = {.tv_sec = (time_t)saved.epoch_seconds, .tv_usec = 0};
if (settimeofday(&time_value, NULL) == 0) ESP_LOGI(TAG, "Restored saved clock time");
}
return true;
}saveSynchronizedTime() · source line 47
static void saveSynchronizedTime(void)
Calls into this documentation:
- Decision
!save_pendingTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
const time_t now = time(NULL); - Decision
now >= 1704067200True- Execute
const time_sync_record_t saved = {TIME_SYNC_RECORD_VERSION, (int64_t)now}; - Decision
!game_storage_write(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY, &saved, sizeof(saved))True- Execute
ESP_LOGW(TAG, "Could not save synchronized time");
FalseContinue after this decision.
FalseContinue after this decision.
- Execute
save_pending = false;
Read original function source
static void saveSynchronizedTime(void)
{
if (!save_pending) return;
const time_t now = time(NULL);
if (now >= 1704067200) {
const time_sync_record_t saved = {TIME_SYNC_RECORD_VERSION, (int64_t)now};
if (!game_storage_write(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY,
&saved, sizeof(saved))) ESP_LOGW(TAG, "Could not save synchronized time");
}
save_pending = false;
}timeSyncDue() · source line 59
bool timeSyncDue(uint32_t now_ms)
- Exit this function
return !attempt_recorded || now_ms - sync_started_at >= TIME_SYNC_INTERVAL_MS;
Read original function source
bool timeSyncDue(uint32_t now_ms)
{
return !attempt_recorded || now_ms - sync_started_at >= TIME_SYNC_INTERVAL_MS;
}timeSyncUpdate() · source line 64
void timeSyncUpdate(bool wifi_connected, uint32_t now_ms)
Calls into this documentation:
- Execute
saveSynchronizedTime(); - Decision
sntp_initialized && status == TIME_SYNC_SYNCING && now_ms - sync_started_at >= TIME_SYNC_TIMEOUT_MSTrue- Execute
status = TIME_SYNC_FAILED; - Execute
ESP_LOGW(TAG, "Time sync timed out");
FalseContinue after this decision.
- Decision
sntp_initialized && !timeSyncDue(now_ms)True- Exit this function
return;
FalseContinue after this decision.
- Decision
sntp_initializedTrue- Execute
esp_netif_sntp_deinit(); - Execute
sntp_initialized = false; - Execute
status = TIME_SYNC_OFF;
FalseContinue after this decision.
- Decision
!timeSyncDue(now_ms) && status != TIME_SYNC_WAITING_FOR_WIFITrue- Exit this function
return;
FalseContinue after this decision.
- Decision
!wifi_connectedTrue- Decision
!sntp_initialized && timeSyncDue(now_ms)True- Execute
sync_started_at = now_ms; - Execute
attempt_recorded = true; - Execute
status = TIME_SYNC_WAITING_FOR_WIFI;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
status == TIME_SYNC_SYNCHRONIZEDTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
const esp_sntp_config_t configuration = { .smooth_sync = false, .server_from_dhcp = false, .wait_for_sync = false, .start = true, .sync_cb = time_sync_callback, .renew_servers_after_new_IP = false, .ip_event_to_renew = IP_EVENT_STA_GOT_IP, .index_of_first_server = 0, .num_of_servers = 1, .servers = {"se.pool.ntp.org"}, }; - Execute
const esp_err_t result = esp_netif_sntp_init(&configuration); - Decision
result != ESP_OKTrue- Execute
status = TIME_SYNC_FAILED; - Execute
ESP_LOGW(TAG, "Time sync start failed: %s", esp_err_to_name(result)); - Exit this function
return;
FalseContinue after this decision.
- Execute
sntp_initialized = true; - Execute
sync_started_at = now_ms; - Execute
attempt_recorded = true; - Execute
status = TIME_SYNC_SYNCING; - Execute
ESP_LOGI(TAG, "Time sync started");
Read original function source
void timeSyncUpdate(bool wifi_connected, uint32_t now_ms)
{
saveSynchronizedTime();
if (sntp_initialized && status == TIME_SYNC_SYNCING &&
now_ms - sync_started_at >= TIME_SYNC_TIMEOUT_MS) {
status = TIME_SYNC_FAILED;
ESP_LOGW(TAG, "Time sync timed out");
}
if (sntp_initialized && !timeSyncDue(now_ms)) return;
if (sntp_initialized) {
esp_netif_sntp_deinit();
sntp_initialized = false;
status = TIME_SYNC_OFF;
}
if (!timeSyncDue(now_ms) && status != TIME_SYNC_WAITING_FOR_WIFI) return;
if (!wifi_connected) {
if (!sntp_initialized && timeSyncDue(now_ms)) {
sync_started_at = now_ms;
attempt_recorded = true;
status = TIME_SYNC_WAITING_FOR_WIFI;
}
return;
}
if (status == TIME_SYNC_SYNCHRONIZED) return;
const esp_sntp_config_t configuration = {
.smooth_sync = false,
.server_from_dhcp = false,
.wait_for_sync = false,
.start = true,
.sync_cb = time_sync_callback,
.renew_servers_after_new_IP = false,
.ip_event_to_renew = IP_EVENT_STA_GOT_IP,
.index_of_first_server = 0,
.num_of_servers = 1,
.servers = {"se.pool.ntp.org"},
};
const esp_err_t result = esp_netif_sntp_init(&configuration);
if (result != ESP_OK) {
status = TIME_SYNC_FAILED;
ESP_LOGW(TAG, "Time sync start failed: %s", esp_err_to_name(result));
return;
}
sntp_initialized = true;
sync_started_at = now_ms;
attempt_recorded = true;
status = TIME_SYNC_SYNCING;
ESP_LOGI(TAG, "Time sync started");
}timeSyncStop() · source line 114
void timeSyncStop(void)
- Decision
sntp_initializedTrue- Execute
esp_netif_sntp_deinit();
FalseContinue after this decision.
- Execute
sntp_initialized = false; - Execute
status = TIME_SYNC_OFF;
Read original function source
void timeSyncStop(void)
{
if (sntp_initialized) esp_netif_sntp_deinit();
sntp_initialized = false;
status = TIME_SYNC_OFF;
}timeSyncAbandonAttempt() · source line 121
void timeSyncAbandonAttempt(void)
- Decision
status == TIME_SYNC_WAITING_FOR_WIFI || status == TIME_SYNC_SYNCINGTrue- Execute
status = TIME_SYNC_FAILED;
FalseContinue after this decision.
Read original function source
void timeSyncAbandonAttempt(void)
{
if (status == TIME_SYNC_WAITING_FOR_WIFI || status == TIME_SYNC_SYNCING) status = TIME_SYNC_FAILED;
}timeSyncStatus() · source line 126
time_sync_status_t timeSyncStatus(void)
- Exit this function
return status;
Read original function source
time_sync_status_t timeSyncStatus(void)
{
return status;
}timeSyncStatusText() · source line 131
const char *timeSyncStatusText(void)
- Select a case
statusEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case TIME_SYNC_WAITING_FOR_WIFI: - Exit this function
return "TIME WAITING FOR WIFI"; - Case / label
case TIME_SYNC_SYNCING: - Exit this function
return "TIME SYNCING..."; - Case / label
case TIME_SYNC_SYNCHRONIZED: - Exit this function
return "TIME SYNCHRONIZED"; - Case / label
case TIME_SYNC_FAILED: - Exit this function
return "TIME SYNC FAILED"; - Case / label
default: - Exit this function
return "TIME SYNC OFF";
Read original function source
const char *timeSyncStatusText(void)
{
switch (status) {
case TIME_SYNC_WAITING_FOR_WIFI: return "TIME WAITING FOR WIFI";
case TIME_SYNC_SYNCING: return "TIME SYNCING...";
case TIME_SYNC_SYNCHRONIZED: return "TIME SYNCHRONIZED";
case TIME_SYNC_FAILED: return "TIME SYNC FAILED";
default: return "TIME SYNC OFF";
}
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "time_sync.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_netif_sntp.h"
#include "game_storage.h"
#include <sys/time.h>
#include <time.h>
#define TIME_SYNC_TIMEOUT_MS 20000U
#define TIME_SYNC_INTERVAL_MS (6U * 60U * 60U * 1000U)
#define TIME_SYNC_STORAGE_NAMESPACE "arcade_clock"
#define TIME_SYNC_STORAGE_KEY "last_good_time"
#define TIME_SYNC_RECORD_VERSION 1U
typedef struct { uint32_t version; int64_t epoch_seconds; } time_sync_record_t;
static const char *TAG = "time_sync";
static bool sntp_initialized;
static time_sync_status_t status = TIME_SYNC_OFF;
static uint32_t sync_started_at;
static bool attempt_recorded;
static bool save_pending;
static void time_sync_callback(struct timeval *time_value)
{
(void)time_value;
status = TIME_SYNC_SYNCHRONIZED;
save_pending = true;
ESP_LOGI(TAG, "Time synchronized");
}
bool timeSyncInitialize(void)
{
bool found = false;
time_sync_record_t saved = {0};
if (!game_storage_read(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY,
&saved, sizeof(saved), &found)) return false;
if (found && saved.version == TIME_SYNC_RECORD_VERSION && saved.epoch_seconds >= 1704067200LL) {
const struct timeval time_value = {.tv_sec = (time_t)saved.epoch_seconds, .tv_usec = 0};
if (settimeofday(&time_value, NULL) == 0) ESP_LOGI(TAG, "Restored saved clock time");
}
return true;
}
static void saveSynchronizedTime(void)
{
if (!save_pending) return;
const time_t now = time(NULL);
if (now >= 1704067200) {
const time_sync_record_t saved = {TIME_SYNC_RECORD_VERSION, (int64_t)now};
if (!game_storage_write(TIME_SYNC_STORAGE_NAMESPACE, TIME_SYNC_STORAGE_KEY,
&saved, sizeof(saved))) ESP_LOGW(TAG, "Could not save synchronized time");
}
save_pending = false;
}
bool timeSyncDue(uint32_t now_ms)
{
return !attempt_recorded || now_ms - sync_started_at >= TIME_SYNC_INTERVAL_MS;
}
void timeSyncUpdate(bool wifi_connected, uint32_t now_ms)
{
saveSynchronizedTime();
if (sntp_initialized && status == TIME_SYNC_SYNCING &&
now_ms - sync_started_at >= TIME_SYNC_TIMEOUT_MS) {
status = TIME_SYNC_FAILED;
ESP_LOGW(TAG, "Time sync timed out");
}
if (sntp_initialized && !timeSyncDue(now_ms)) return;
if (sntp_initialized) {
esp_netif_sntp_deinit();
sntp_initialized = false;
status = TIME_SYNC_OFF;
}
if (!timeSyncDue(now_ms) && status != TIME_SYNC_WAITING_FOR_WIFI) return;
if (!wifi_connected) {
if (!sntp_initialized && timeSyncDue(now_ms)) {
sync_started_at = now_ms;
attempt_recorded = true;
status = TIME_SYNC_WAITING_FOR_WIFI;
}
return;
}
if (status == TIME_SYNC_SYNCHRONIZED) return;
const esp_sntp_config_t configuration = {
.smooth_sync = false,
.server_from_dhcp = false,
.wait_for_sync = false,
.start = true,
.sync_cb = time_sync_callback,
.renew_servers_after_new_IP = false,
.ip_event_to_renew = IP_EVENT_STA_GOT_IP,
.index_of_first_server = 0,
.num_of_servers = 1,
.servers = {"se.pool.ntp.org"},
};
const esp_err_t result = esp_netif_sntp_init(&configuration);
if (result != ESP_OK) {
status = TIME_SYNC_FAILED;
ESP_LOGW(TAG, "Time sync start failed: %s", esp_err_to_name(result));
return;
}
sntp_initialized = true;
sync_started_at = now_ms;
attempt_recorded = true;
status = TIME_SYNC_SYNCING;
ESP_LOGI(TAG, "Time sync started");
}
void timeSyncStop(void)
{
if (sntp_initialized) esp_netif_sntp_deinit();
sntp_initialized = false;
status = TIME_SYNC_OFF;
}
void timeSyncAbandonAttempt(void)
{
if (status == TIME_SYNC_WAITING_FOR_WIFI || status == TIME_SYNC_SYNCING) status = TIME_SYNC_FAILED;
}
time_sync_status_t timeSyncStatus(void)
{
return status;
}
const char *timeSyncStatusText(void)
{
switch (status) {
case TIME_SYNC_WAITING_FOR_WIFI: return "TIME WAITING FOR WIFI";
case TIME_SYNC_SYNCING: return "TIME SYNCING...";
case TIME_SYNC_SYNCHRONIZED: return "TIME SYNCHRONIZED";
case TIME_SYNC_FAILED: return "TIME SYNC FAILED";
default: return "TIME SYNC OFF";
}
}