DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ntp_service.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ntp_service.cpp
6 * @brief SNTP wall-clock time sync implementation (DETWS_ENABLE_NTP).
7 */
8
9#include "ntp_service.h"
10#include "shared_primitives/http_date.h" // detws_http_date() - the shared IMF-fixdate formatter
11
12#if DETWS_ENABLE_NTP && defined(ARDUINO)
13
14#include <Arduino.h>
15
16// A successful sync moves the clock well past this sentinel (2021-01-01 UTC);
17// a cold-booted RTC sits near the Unix epoch.
18static const time_t DETWS_NTP_PLAUSIBLE_EPOCH = 1609459200;
19
20bool detws_ntp_begin(const char *tz, const char *server1, const char *server2)
21{
22 // configTzTime applies the POSIX TZ and starts the SNTP client (async).
23 configTzTime(tz ? tz : "UTC0", server1, server2);
24 return true;
25}
26
28{
29 return time(nullptr) > DETWS_NTP_PLAUSIBLE_EPOCH;
30}
31
32time_t detws_ntp_epoch()
33{
34 time_t now = time(nullptr);
35 return (now > DETWS_NTP_PLAUSIBLE_EPOCH) ? now : 0;
36}
37
38size_t detws_ntp_http_date(char *out, size_t out_cap)
39{
40 return detws_http_date(detws_ntp_epoch(), out, out_cap);
41}
42
43#else
44
45// Host build: no SNTP. A test seam lets a unit test inject a wall-clock epoch so
46// the Date-header path (and any time-dependent code) is exercisable off-device.
47#include <time.h>
48// All host NTP test-seam state, owned by one instance (internal linkage): the injected
49// wall-clock epoch, so it is one named owner, unreachable from any other translation unit.
50namespace
51{
52struct NtpSvcCtx
53{
54 time_t host_test_epoch = 0;
55};
56NtpSvcCtx s_ntp_svc;
57} // namespace
58void detws_ntp_set_test_epoch(time_t epoch)
59{
60 s_ntp_svc.host_test_epoch = epoch;
61}
62
63bool detws_ntp_begin(const char *tz, const char *server1, const char *server2)
64{
65 (void)tz;
66 (void)server1;
67 (void)server2;
68 return false;
69}
71{
72 return s_ntp_svc.host_test_epoch != 0;
73}
75{
76 return s_ntp_svc.host_test_epoch;
77}
78size_t detws_ntp_http_date(char *out, size_t out_cap)
79{
80 return detws_http_date(detws_ntp_epoch(), out, out_cap);
81}
82
83#endif // DETWS_ENABLE_NTP && ARDUINO
84
85// NTP as a registry time source (defined for both the device and host builds; detws_ntp_epoch is 0
86// until synced / when no test epoch is injected). Register it with detws_time_source_add() so the
87// aggregated detws_time_now() - and the HTTP Date header - can be fed by NTP alongside an RTC / GPS.
88uint32_t ntp_time_source(void)
89{
90 return (uint32_t)detws_ntp_epoch();
91}
Format a Unix epoch as an RFC 7231 IMF-fixdate (one shared copy).
size_t detws_http_date(time_t epoch, char *out, size_t out_cap)
Write epoch as an RFC 7231 IMF-fixdate into out (always GMT).
Definition http_date.h:30
time_t detws_ntp_epoch()
Current Unix epoch seconds, or 0 if not yet synced (or disabled).
uint32_t ntp_time_source(void)
NTP as a time source for the multi-source registry (services/time_source).
void detws_ntp_set_test_epoch(time_t epoch)
bool detws_ntp_synced()
True once a plausible wall-clock time has been obtained from SNTP.
bool detws_ntp_begin(const char *tz, const char *server1, const char *server2)
Start the SNTP client.
size_t detws_ntp_http_date(char *out, size_t out_cap)
Format the current time as an RFC 7231 IMF-fixdate (HTTP Date).
Optional SNTP wall-clock time sync (DETWS_ENABLE_NTP).