ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
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 pc_ntp_service.cpp
6 * @brief SNTP wall-clock time sync implementation (PC_ENABLE_NTP).
7 */
8
9#include "ntp_service.h"
10#include "shared_primitives/http_date.h" // pc_http_date() - the shared IMF-fixdate formatter
11#include <time.h> // time_t / time() - used by both the Arduino SNTP and host test-seam paths
12
13#if PC_ENABLE_NTP && defined(ARDUINO)
14
15#include <Arduino.h>
16
17// A successful sync moves the clock well past this sentinel (2021-01-01 UTC);
18// a cold-booted RTC sits near the Unix epoch.
19static const time_t PC_NTP_PLAUSIBLE_EPOCH = 1609459200;
20
21bool pc_ntp_begin(const char *tz, const char *server1, const char *server2)
22{
23 // configTzTime applies the POSIX TZ and starts the SNTP client (async).
24 configTzTime(tz ? tz : "UTC0", server1, server2);
25 return true;
26}
27
28bool pc_ntp_synced()
29{
30 return time(nullptr) > PC_NTP_PLAUSIBLE_EPOCH;
31}
32
33time_t pc_ntp_epoch()
34{
35 time_t now = time(nullptr);
36 return (now > PC_NTP_PLAUSIBLE_EPOCH) ? now : 0;
37}
38
39size_t pc_ntp_http_date(char *out, size_t out_cap)
40{
41 return pc_http_date(pc_ntp_epoch(), out, out_cap);
42}
43
44#else
45
46// Host build: no SNTP. A test seam lets a unit test inject a wall-clock epoch so
47// the Date-header path (and any time-dependent code) is exercisable off-device.
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 pc_ntp_set_test_epoch(time_t epoch)
59{
60 s_ntp_svc.host_test_epoch = epoch;
61}
62
63bool pc_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 pc_ntp_http_date(char *out, size_t out_cap)
79{
80 return pc_http_date(pc_ntp_epoch(), out, out_cap);
81}
82
83#endif // PC_ENABLE_NTP && ARDUINO
84
85// NTP as a registry time source (defined for both the device and host builds; pc_ntp_epoch is 0
86// until synced / when no test epoch is injected). Register it with pc_time_source_add() so the
87// aggregated pc_time_now() - and the HTTP Date header - can be fed by NTP alongside an RTC / GPS.
88uint32_t pc_ntp_time_source(void)
89{
90 return (uint32_t)pc_ntp_epoch();
91}
Render a Unix epoch as an RFC 7231 IMF-fixdate.
uint8_t pc_http_date(time_t epoch, char *out, uint32_t out_cap)
Write epoch into out as an IMF-fixdate in GMT.
Definition http_date.h:41
size_t pc_ntp_http_date(char *out, size_t out_cap)
Format the current time as an RFC 7231 IMF-fixdate (HTTP Date).
uint32_t pc_ntp_time_source(void)
NTP as a time source for the multi-source registry (services/timing_position/time_source).
bool pc_ntp_begin(const char *tz, const char *server1, const char *server2)
Start the SNTP client.
time_t pc_ntp_epoch()
Current Unix epoch seconds, or 0 if not yet synced (or disabled).
bool pc_ntp_synced()
True once a plausible wall-clock time has been obtained from SNTP.
void pc_ntp_set_test_epoch(time_t epoch)