File espos_time_policy.h¶
File List > espos_time > include > espos_time_policy.h
Go to the documentation of this file
/*
* SPDX-FileCopyrightText: 2026 Dirk Wahrheit
* SPDX-License-Identifier: Apache-2.0
*
* espos_time policy — the clock's decisions as pure C.
*
* Three things about a wall clock are worth getting right and none of them
* need a platform: which source is allowed to overwrite which (ranking), when
* a time carried through a deep sleep has aged past usefulness (staleness),
* and how an instant is written down (ISO 8601 UTC with milliseconds). All
* three live here, driven by an injected monotonic clock, so a host test can
* step time forward by a day without sleeping — the same shape as
* espos_wifi_sm, espos_sk_token_sm and espos_health_policy.
*
* The instant itself is kept as an offset: `epoch_at_zero_ms` is what the wall
* clock read when the monotonic counter was zero. Reading the time is then one
* addition, and — the point of the exercise — a time learned late still dates
* an event that happened early, because the offset applies to every monotonic
* stamp ever taken, not only to the ones after the sync.
*
* Threading: none. The caller (espos_time.c) serialises access under its own
* mutex; nothing here allocates, blocks or calls out.
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
#include "espos_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Everything the policy needs from the outside world. */
typedef struct {
/* Monotonic milliseconds since boot. 64-bit on purpose: this one must not
* wrap, because it is the base every wall-clock reading is built on. */
int64_t (*now_ms)(void *ctx);
} espos_time_policy_port_t;
typedef struct espos_time_policy {
const espos_time_policy_port_t *port;
void *ctx;
espos_time_src_t src; /* NONE until something sets the clock */
int64_t epoch_at_zero_ms; /* unix ms the monotonic counter's zero corresponds to */
int64_t set_at_mono_ms; /* when the current source last set it */
int64_t prior_age_ms; /* age the value already had when it was adopted (a deep sleep) */
uint32_t stale_after_h; /* an RTC time older than this is not "synced"; 0 = never stale */
uint32_t sets; /* how often a source set the clock, for the status document */
} espos_time_policy_t;
void espos_time_policy_init(espos_time_policy_t *p, const espos_time_policy_port_t *port, void *ctx,
uint32_t stale_after_h);
esp_err_t espos_time_policy_set(espos_time_policy_t *p, int64_t unix_ms, espos_time_src_t src);
esp_err_t espos_time_policy_set_aged(espos_time_policy_t *p, int64_t unix_ms, espos_time_src_t src,
int64_t prior_age_ms);
int64_t espos_time_policy_now_ms(const espos_time_policy_t *p);
int64_t espos_time_policy_at_ms(const espos_time_policy_t *p, int64_t mono_ms);
bool espos_time_policy_is_synced(const espos_time_policy_t *p);
size_t espos_time_iso8601_format(int64_t unix_ms, char *buf, size_t n);
int64_t espos_time_iso8601_parse(const char *s);
#ifdef __cplusplus
}
#endif