From 40922fd29a6bdfcf3b13da612acef865cc86eb30 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 10:19:38 +0200 Subject: [PATCH 01/12] feat: Initial tested implementation of SNTP --- CMakeLists.txt | 2 +- .../Communication/Ethernet/NewEthernet.hpp | 2 +- .../Services/Communication/SNTP/SNTP.hpp | 146 +++++++- .../Services/Communication/SNTP/SNTP.cpp | 347 ++++++++++++++++-- 4 files changed, 457 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4d629e3e..e0f8d136e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,7 +252,7 @@ if(CMAKE_CROSSCOMPILING) ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/core/ipv4/ip4.c ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/core/ipv4/ip4_addr.c ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/core/ipv4/ip4_frag.c - ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/apps/sntp/sntp.c + #${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/apps/sntp/sntp.c ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Middlewares/Third_Party/LwIP/src/netif/ethernet.c ) diff --git a/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp b/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp index 779adce68..f49abc904 100644 --- a/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp +++ b/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp @@ -259,7 +259,7 @@ struct EthernetDomain { if (!sntp_started && sntp_server != nullptr && sntp_server[0] != '\0' && netif_is_link_up(&gnetif)) { - SNTP::sntp_update(sntp_server); + // SNTP::sntp_update(sntp_server); sntp_started = true; } } diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index a87592016..39b070de5 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -7,20 +7,138 @@ #pragma once -#include "lwip/apps/sntp.h" +// #include "lwip/apps/sntp.h" +#include "lwip/udp.h" #include "HALAL/Models/IPV4/IPV4.hpp" #include "C++Utilities/CppUtils.hpp" +#include "HALAL/Services/Time/Scheduler.hpp" -class SNTP { -public: - static constexpr const char* DEFAULT_SERVER_IP = "192.168.0.9"; - - static void sntp_update( - uint8_t address_head, - uint8_t address_second, - uint8_t address_third, - uint8_t address_last - ); - static void sntp_update(string ip); - static void sntp_update(); -}; +namespace ST_LIB { + +struct SNTP { + /* config values for SNTP */ + + static constexpr uint16_t PORT = 8123; + static constexpr uint8_t MAX_SERVERS = 1; + static constexpr uint32_t RETRY_TIMEOUT = 15000; + static constexpr uint32_t RECV_TIMEOUT = 15000; + static constexpr uint32_t UPDATE_DELAY = 3600000; + + static constexpr uint8_t OPMODE_POLL = 0; + static constexpr uint8_t OPMODE_LISTENONLY = 1; + + /* chosen opmode */ + static constexpr uint8_t MODE = SNTP::OPMODE_POLL; + + /* SNTP specific values */ + + /* kiss-of-death packet */ + static constexpr uint8_t ERR_KOD = 1; + + static constexpr uint16_t MSG_LEN = 48; + + /* NOTE: We don't care about leap seconds so we'll use no-warning */ + static constexpr uint8_t LEAP_INDICATOR_NO_WARNING = 0x00 << 6; + static constexpr uint8_t LEAP_INDICATOR_LAST_MINUTE_61_SEC = 0x01 << 6; + static constexpr uint8_t LEAP_INDICATOR_LAST_MINUTE_59_SEC = 0x02 << 6; + static constexpr uint8_t LEAP_INDICATOR_ALARM_CONDITION = 0x03 << 6; + + /* SNTP Version 4 */ + static constexpr uint8_t VERSION = 4 << 3; + + static constexpr uint8_t MODE_MASK = 0x07; + static constexpr uint8_t MODE_CLIENT = 0x03; + static constexpr uint8_t MODE_SERVER = 0x04; + static constexpr uint8_t MODE_BROADCAST = 0x05; + + static constexpr uint8_t OFFSET_STRATUM = 1; + static constexpr uint8_t STRATUM_KOD = 0x00; + + static constexpr uint8_t OFFSET_TRANSMIT_TIME = 40; + + struct Server { +#if SNTP_SERVER_DNS + const char *name; +#endif /* SNTP_SERVER_DNS */ + ip_addr_t addr; +#if SNTP_MONITOR_SERVER_REACHABILITY + /** Reachability shift register as described in RFC 5905 */ + u8_t reachability; +#endif /* SNTP_MONITOR_SERVER_REACHABILITY */ + }; + + /** + * 64-bit NTP timestamp, in network byte order. + */ + struct Time { + uint32_t sec; + uint32_t frac; + }; + + struct Timestamps { +#if SNTP_COMP_ROUNDTRIP || SNTP_CHECK_RESPONSE >= 2 + SNTP::Time orig; + SNTP::Time recv; +#endif + SNTP::Time xmit; + }; + +#pragma pack(push, 1) + struct Message { + uint8_t li_vn_mode; + uint8_t stratum; + uint8_t poll; + uint8_t precision; + uint32_t root_delay; + uint32_t root_dispersion; + uint32_t reference_identifier; + uint32_t reference_timestamp[2]; + uint32_t originate_timestamp[2]; + uint32_t receive_timestamp[2]; + uint32_t transmit_timestamp[2]; + }; +#pragma pack(pop) + + static inline SNTP::Server servers[SNTP::MAX_SERVERS]; + +#if SNTP_SUPPORT_MULTIPLE_SERVERS + /** The currently used server (initialized to 0) */ + static inline uint8_t sntp_current_server; + static inline void try_next_server(const ip_addr_t *server_addr) { + #error SNTP multiple servers not supported. + } +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + static constexpr uint8_t current_server = 0; +#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ + + /** The UDP pcb used by the SNTP client */ + static inline struct udp_pcb *pcb; + static inline uint32_t retry_timeout = SNTP::RETRY_TIMEOUT; + + static void start(ip_addr_t address); + static void start(const char *ip); + static void start(uint8_t address_head, uint8_t address_second, uint8_t address_third, uint8_t address_last); + static void stop(void); + + /* internals */ + + static inline uint16_t request_task_id = Scheduler::INVALID_ID; + static inline uint16_t try_next_server_task_id = Scheduler::INVALID_ID; + static inline uint8_t opmode = SNTP::MODE; + + static void initialize_request(SNTP::Message *req); + static void send_request(const ip_addr_t *server_addr); + static void retry(void); + static void request(void); + static void process(const SNTP::Timestamps *timestamps); + static void recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + +#if !SNTP_SUPPORT_MULTIPLE_SERVERS + static constexpr void (*try_next_server)(void) = SNTP::retry; +#endif +}; // struct SNTP +}; // ST_LIB + +#if 0 +static constexpr const char* DEFAULT_SERVER_IP = "192.168.0.9"; +#endif diff --git a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp index 4b531be44..cccaee013 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -8,40 +8,339 @@ #include "HALAL/Services/Communication/SNTP/SNTP.hpp" #include "HALAL/Services/Time/RTC.hpp" +/* This implementation uses Lwip code */ + #define SUBSECONDS_PER_SECOND 32767 #define TRANSFORMATION_FACTOR (SUBSECONDS_PER_SECOND / 999999.0) -namespace { +/* Start offset of the timestamps to extract from the SNTP packet */ +#define SNTP_OFFSET_TIMESTAMPS \ + (SNTP::OFFSET_TRANSMIT_TIME + 8 - sizeof(SNTP::Timestamps)) -void configure_sntp_server(const ip_addr_t& address) { - if (sntp_enabled()) { - sntp_stop(); - } +/* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */ +#define DIFF_SEC_1970_2036 ((u32_t)2085978496L) - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setserver(0, &address); - sntp_init(); -} +#define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32)) -} // namespace +# define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \ + u32_t sec_, usec_; \ + SNTP_GET_SYSTEM_TIME(sec_, usec_); \ + (s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \ + (f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \ + } while (0) -void SNTP::sntp_update( - uint8_t address_head, - uint8_t address_second, - uint8_t address_third, - uint8_t address_last -) { +#define SNTP_SET_SYSTEM_TIME_US(sec, us) stlib_sntp_set_time((sec), (us)) +#define SNTP_GET_SYSTEM_TIME(sec, us) \ + do { \ + (sec) = stlib_sntp_get_rtc_seconds(); \ + (us) = stlib_sntp_get_rtc_microseconds(); \ + } while (0) + +#define SNTP_SET_SYSTEM_TIME_NTP(s, f) \ + SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f)) + +namespace ST_LIB { + +void SNTP::start(uint8_t address_head, uint8_t address_second, + uint8_t address_third, uint8_t address_last) +{ ip_addr_t address; IP_ADDR4(&address, address_head, address_second, address_third, address_last); - configure_sntp_server(address); + SNTP::start(address); +} + +void SNTP::start(const char *ip) { + IPV4 target(ip); + SNTP::start(target.address); +} + +void SNTP::start(ip_addr_t address) { + SNTP::servers[0].addr = address; + + if (SNTP::pcb == NULL) { + SNTP::pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + LWIP_ASSERT("Failed to allocate udp pcb for sntp client", SNTP::pcb != NULL); + if (SNTP::pcb != NULL) { + udp_recv(SNTP::pcb, SNTP::recv, NULL); + + if (SNTP::opmode == SNTP::MODE) { +#if SNTP_STARTUP_DELAY + request_task_id = + Scheduler::set_timeout((uint32_t)SNTP_STARTUP_DELAY_FUNC*1000, SNTP::request); +#else + SNTP::request(); +#endif + } else if (SNTP::opmode == SNTP::OPMODE_LISTENONLY) { + ip_set_option(SNTP::pcb, SOF_BROADCAST); + udp_bind(SNTP::pcb, IP_ANY_TYPE, SNTP::PORT); + } + } + } +} + +void SNTP::stop(void) { + if (SNTP::pcb != NULL) { +#if SNTP_MONITOR_SERVER_REACHABILITY + for (uint8_t i = 0; i < SNTP_MAX_SERVERS; i++) { + SNTP::servers[i].reachability = 0; + } +#endif + Scheduler::cancel_timeout(SNTP::request_task_id); + Scheduler::cancel_timeout(SNTP::try_next_server_task_id); + udp_remove(SNTP::pcb); + SNTP::pcb = NULL; + } +} + +void SNTP::initialize_request(SNTP::Message *req) +{ + memset(req, 0, SNTP::MSG_LEN); + req->li_vn_mode = SNTP::LEAP_INDICATOR_NO_WARNING | + SNTP::VERSION | SNTP::MODE_CLIENT; + +//#if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP + { + s32_t secs; + uint32_t sec, frac; + /* Get the transmit timestamp */ + SNTP_GET_SYSTEM_TIME_NTP(secs, frac); + sec = lwip_htonl((uint32_t)secs); + frac = lwip_htonl(frac); + +# if SNTP_CHECK_RESPONSE >= 2 + sntp_last_timestamp_sent.sec = sec; + sntp_last_timestamp_sent.frac = frac; +# endif + req->transmit_timestamp[0] = sec; + req->transmit_timestamp[1] = frac; + } +//#endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */ } -void SNTP::sntp_update(string ip) { - IPV4 target(ip.c_str()); - configure_sntp_server(target.address); +void SNTP::send_request(const ip_addr_t *server_addr) +{ + struct pbuf *p; + + LWIP_ASSERT("server_addr != NULL", server_addr != NULL); + + p = pbuf_alloc(PBUF_TRANSPORT, SNTP::MSG_LEN, PBUF_RAM); + if (p != NULL) { + SNTP::Message *sntpmsg = (SNTP::Message*)p->payload; + SNTP::initialize_request(sntpmsg); + /* send request */ + udp_sendto(SNTP::pcb, p, server_addr, SNTP::PORT); + /* free the pbuf after sending it */ + pbuf_free(p); +#if SNTP_MONITOR_SERVER_REACHABILITY + /* indicate new packet has been sent */ + SNTP::servers[SNTP::current_server].reachability <<= 1; +#endif /* SNTP_MONITOR_SERVER_REACHABILITY */ + /* set up receive timeout: try next server or retry on timeout */ + SNTP::try_next_server_task_id = + Scheduler::set_timeout((uint32_t)SNTP::RECV_TIMEOUT * 1000, SNTP::try_next_server); +#if SNTP_CHECK_RESPONSE >= 1 + /* save server address to verify it in sntp_recv */ + ip_addr_copy(sntp_last_server_address, *server_addr); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + } else { + /* out of memory: set up a timer to send a retry */ + SNTP::request_task_id = + Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT*1000, SNTP::request); + } +} + +void SNTP::retry(void) { + /* set up a timer to send a retry and increase the retry delay */ + SNTP::request_task_id = + Scheduler::set_timeout(SNTP::retry_timeout*1000, SNTP::request); + +#if SNTP_RETRY_TIMEOUT_EXP + { + uint32_t new_retry_timeout; + /* increase the timeout for next retry */ + new_retry_timeout = SNTP::retry_timeout << 1; + /* limit to maximum timeout and prevent overflow */ + if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && + (new_retry_timeout > SNTP::retry_timeout)) { + SNTP::retry_timeout = new_retry_timeout; + } + } +#endif /* SNTP_RETRY_TIMEOUT_EXP */ +} + +void SNTP::request(void) { + ip_addr_t sntp_server_address; + err_t err; + +#if SNTP_SERVER_DNS + if (SNTP::servers[SNTP::current_server].name) { + /* always resolve the name and rely on dns-internal caching & timeout */ + ip_addr_set_zero(&SNTP::servers[SNTP::current_server].addr); + err = dns_gethostbyname(SNTP::servers[SNTP::current_server].name, &sntp_server_address, + SNTP::dns_found, NULL); + if (err == ERR_INPROGRESS) { + /* DNS request sent, wait for sntp_dns_found being called */ + return; + } else if (err == ERR_OK) { + SNTP::servers[SNTP::current_server].addr = sntp_server_address; + } + } else +#endif /* SNTP_SERVER_DNS */ + { + sntp_server_address = SNTP::servers[SNTP::current_server].addr; + err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK; + } + + if (err == ERR_OK) { + SNTP::send_request(&sntp_server_address); + } else { + /* address conversion failed, try another server */ + SNTP::try_next_server_task_id = + Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT*1000, SNTP::try_next_server); + } +} + +void SNTP::process(const SNTP::Timestamps *timestamps) +{ + s32_t sec; + u32_t frac; + + sec = (s32_t)lwip_ntohl(timestamps->xmit.sec); + frac = lwip_ntohl(timestamps->xmit.frac); + +#if SNTP_COMP_ROUNDTRIP +# if SNTP_CHECK_RESPONSE >= 2 + if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0) +# endif + { + s32_t dest_sec; + u32_t dest_frac; + u32_t step_sec; + + /* Get the destination time stamp, i.e. the current system time */ + SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac); + + step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec) + : ((u32_t)dest_sec - (u32_t)sec); + /* In order to avoid overflows, skip the compensation if the clock step + * is larger than about 34 years. */ + if ((step_sec >> 30) == 0) { + s64_t t1, t2, t3, t4; + + t4 = SNTP_SEC_FRAC_TO_S64(dest_sec, dest_frac); + t3 = SNTP_SEC_FRAC_TO_S64(sec, frac); + t1 = SNTP_TIMESTAMP_TO_S64(timestamps->orig); + t2 = SNTP_TIMESTAMP_TO_S64(timestamps->recv); + /* Clock offset calculation according to RFC 4330 */ + t4 += ((t2 - t1) + (t3 - t4)) / 2; + + sec = (s32_t)((u64_t)t4 >> 32); + frac = (u32_t)((u64_t)t4); + } + } +#endif /* SNTP_COMP_ROUNDTRIP */ + + SNTP_SET_SYSTEM_TIME_NTP(sec, frac); + LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */ +} + +void SNTP::recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + SNTP::Timestamps timestamps; + uint8_t mode; + uint8_t stratum; + err_t err; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + + err = ERR_ARG; +#if SNTP_CHECK_RESPONSE >= 1 + /* check server address and port */ + if (((SNTP::opmode != SNTP::OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && + (port == SNTP::PORT)) +#else /* SNTP_CHECK_RESPONSE >= 1 */ + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(port); +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + { + /* process the response */ + if (p->tot_len == SNTP::MSG_LEN) { + mode = pbuf_get_at(p, 0) & SNTP::MODE_MASK; + /* if this is a SNTP response... */ + if (((SNTP::opmode == SNTP::OPMODE_POLL) && (mode == SNTP::MODE_SERVER)) || + ((SNTP::opmode == SNTP::OPMODE_LISTENONLY) && (mode == SNTP::MODE_BROADCAST))) { + stratum = pbuf_get_at(p, SNTP::OFFSET_STRATUM); + + if (stratum == SNTP::STRATUM_KOD) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + err = SNTP::ERR_KOD; + } else { + pbuf_copy_partial(p, ×tamps, sizeof(timestamps), SNTP_OFFSET_TIMESTAMPS); +#if SNTP_CHECK_RESPONSE >= 2 + /* check originate_timetamp against sntp_last_timestamp_sent */ + if (timestamps.orig.sec != sntp_last_timestamp_sent.sec || + timestamps.orig.frac != sntp_last_timestamp_sent.frac) { + // Invalid originate timestamp in response (ignore) + } else +#endif /* SNTP_CHECK_RESPONSE >= 2 */ + /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ + { + /* correct answer */ + err = ERR_OK; + } + } + } else { + // Invalid mode in response `mode` + /* wait for correct response */ + err = ERR_TIMEOUT; + } + } else { + // Invalid packet length `p->tot_len` (ignore) + } + } +#if SNTP_CHECK_RESPONSE >= 1 + else { + /* packet from wrong remote address or port, wait for correct response */ + err = ERR_TIMEOUT; + } +#endif /* SNTP_CHECK_RESPONSE >= 1 */ + + pbuf_free(p); + + if (err == ERR_OK) { + /* correct packet received: process it it */ + SNTP::process(×tamps); + +#if SNTP_MONITOR_SERVER_REACHABILITY + /* indicate that server responded */ + SNTP::servers[SNTP::current_server].reachability |= 1; +#endif /* SNTP_MONITOR_SERVER_REACHABILITY */ + /* Set up timeout for next request (only if poll response was received)*/ + if (SNTP::opmode == SNTP::OPMODE_POLL) { + u32_t sntp_update_delay; + Scheduler::cancel_timeout(SNTP::try_next_server_task_id); + Scheduler::cancel_timeout(SNTP::request_task_id); + + /* Correct response, reset retry timeout */ + SNTP::retry_timeout = SNTP::RETRY_TIMEOUT; + + sntp_update_delay = (u32_t)SNTP::UPDATE_DELAY; + SNTP::request_task_id = + Scheduler::set_timeout(sntp_update_delay, SNTP::request); + } + } else if (err == SNTP::ERR_KOD) { + /* KOD errors are only processed in case of an explicit poll response */ + if (SNTP::opmode == SNTP::OPMODE_POLL) { + /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ + SNTP::try_next_server(); + } + } else { + /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */ + } } -void SNTP::sntp_update() { sntp_update(DEFAULT_SERVER_IP); } +}; // namespace ST_LIB extern "C" void stlib_sntp_set_rtc( uint16_t counter, @@ -55,7 +354,7 @@ extern "C" void stlib_sntp_set_rtc( Global_RTC::set_rtc_data(counter, second, minute, hour, day, month, year); } -extern "C" u32_t stlib_sntp_get_rtc_seconds() { +extern "C" uint32_t stlib_sntp_get_rtc_seconds() { if (!Global_RTC::has_valid_time()) { return 0; } @@ -70,11 +369,11 @@ extern "C" u32_t stlib_sntp_get_rtc_seconds() { nowtm->tm_hour = rtc_time.hour; nowtm->tm_min = rtc_time.minute; nowtm->tm_sec = rtc_time.second; - u32_t sec = mktime(nowtm); + uint32_t sec = mktime(nowtm); return sec; } -extern "C" u32_t stlib_sntp_get_rtc_microseconds() { +extern "C" uint32_t stlib_sntp_get_rtc_microseconds() { if (!Global_RTC::has_valid_time()) { return 0; } From e19191e8d13546a62c9f767b6d46a5d6ea309ea7 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 10:43:09 +0200 Subject: [PATCH 02/12] remove old sntp from EthernetDomain --- Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp b/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp index f49abc904..5c3f5caa0 100644 --- a/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp +++ b/Inc/HALAL/Services/Communication/Ethernet/NewEthernet.hpp @@ -240,8 +240,6 @@ struct EthernetDomain { } // Runtime object struct Instance { - const char* sntp_server{nullptr}; - bool sntp_started{false}; constexpr Instance() {} void update() { @@ -256,12 +254,6 @@ struct EthernetDomain { netif_set_up(&gnetif); } } - - if (!sntp_started && sntp_server != nullptr && sntp_server[0] != '\0' && - netif_is_link_up(&gnetif)) { - // SNTP::sntp_update(sntp_server); - sntp_started = true; - } } bool is_connected() { return netif_is_link_up(&gnetif); } }; From 5110cb2722e51cee80f91e88e6e7ab442f25c7a7 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 12:53:31 +0200 Subject: [PATCH 03/12] formatting part 1 --- .../Services/Communication/SNTP/SNTP.hpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index 39b070de5..824440196 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -21,8 +21,8 @@ struct SNTP { static constexpr uint16_t PORT = 8123; static constexpr uint8_t MAX_SERVERS = 1; static constexpr uint32_t RETRY_TIMEOUT = 15000; - static constexpr uint32_t RECV_TIMEOUT = 15000; - static constexpr uint32_t UPDATE_DELAY = 3600000; + static constexpr uint32_t RECV_TIMEOUT = 15000; + static constexpr uint32_t UPDATE_DELAY = 3600000; static constexpr uint8_t OPMODE_POLL = 0; static constexpr uint8_t OPMODE_LISTENONLY = 1; @@ -38,27 +38,27 @@ struct SNTP { static constexpr uint16_t MSG_LEN = 48; /* NOTE: We don't care about leap seconds so we'll use no-warning */ - static constexpr uint8_t LEAP_INDICATOR_NO_WARNING = 0x00 << 6; + static constexpr uint8_t LEAP_INDICATOR_NO_WARNING = 0x00 << 6; static constexpr uint8_t LEAP_INDICATOR_LAST_MINUTE_61_SEC = 0x01 << 6; static constexpr uint8_t LEAP_INDICATOR_LAST_MINUTE_59_SEC = 0x02 << 6; - static constexpr uint8_t LEAP_INDICATOR_ALARM_CONDITION = 0x03 << 6; + static constexpr uint8_t LEAP_INDICATOR_ALARM_CONDITION = 0x03 << 6; /* SNTP Version 4 */ static constexpr uint8_t VERSION = 4 << 3; - static constexpr uint8_t MODE_MASK = 0x07; - static constexpr uint8_t MODE_CLIENT = 0x03; - static constexpr uint8_t MODE_SERVER = 0x04; + static constexpr uint8_t MODE_MASK = 0x07; + static constexpr uint8_t MODE_CLIENT = 0x03; + static constexpr uint8_t MODE_SERVER = 0x04; static constexpr uint8_t MODE_BROADCAST = 0x05; static constexpr uint8_t OFFSET_STRATUM = 1; - static constexpr uint8_t STRATUM_KOD = 0x00; + static constexpr uint8_t STRATUM_KOD = 0x00; static constexpr uint8_t OFFSET_TRANSMIT_TIME = 40; struct Server { #if SNTP_SERVER_DNS - const char *name; + const char* name; #endif /* SNTP_SERVER_DNS */ ip_addr_t addr; #if SNTP_MONITOR_SERVER_REACHABILITY @@ -104,7 +104,7 @@ struct SNTP { #if SNTP_SUPPORT_MULTIPLE_SERVERS /** The currently used server (initialized to 0) */ static inline uint8_t sntp_current_server; - static inline void try_next_server(const ip_addr_t *server_addr) { + static inline void try_next_server(const ip_addr_t* server_addr) { #error SNTP multiple servers not supported. } #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ @@ -112,11 +112,11 @@ struct SNTP { #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ /** The UDP pcb used by the SNTP client */ - static inline struct udp_pcb *pcb; + static inline struct udp_pcb* pcb; static inline uint32_t retry_timeout = SNTP::RETRY_TIMEOUT; static void start(ip_addr_t address); - static void start(const char *ip); + static void start(const char* ip); static void start(uint8_t address_head, uint8_t address_second, uint8_t address_third, uint8_t address_last); static void stop(void); @@ -126,12 +126,12 @@ struct SNTP { static inline uint16_t try_next_server_task_id = Scheduler::INVALID_ID; static inline uint8_t opmode = SNTP::MODE; - static void initialize_request(SNTP::Message *req); - static void send_request(const ip_addr_t *server_addr); + static void initialize_request(SNTP::Message* req); + static void send_request(const ip_addr_t* server_addr); static void retry(void); static void request(void); - static void process(const SNTP::Timestamps *timestamps); - static void recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + static void process(const SNTP::Timestamps* timestamps); + static void recv(void *arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port); #if !SNTP_SUPPORT_MULTIPLE_SERVERS static constexpr void (*try_next_server)(void) = SNTP::retry; From c7c5b7ec969c9292f57fef408bfa6a4395a5d0f4 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 13:05:28 +0200 Subject: [PATCH 04/12] formatting part 2 --- .../Services/Communication/SNTP/SNTP.hpp | 25 ++-- .../Services/Communication/SNTP/SNTP.cpp | 110 +++++++++--------- 2 files changed, 72 insertions(+), 63 deletions(-) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index 824440196..da8e31312 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -85,10 +85,10 @@ struct SNTP { #pragma pack(push, 1) struct Message { - uint8_t li_vn_mode; - uint8_t stratum; - uint8_t poll; - uint8_t precision; + uint8_t li_vn_mode; + uint8_t stratum; + uint8_t poll; + uint8_t precision; uint32_t root_delay; uint32_t root_dispersion; uint32_t reference_identifier; @@ -105,9 +105,9 @@ struct SNTP { /** The currently used server (initialized to 0) */ static inline uint8_t sntp_current_server; static inline void try_next_server(const ip_addr_t* server_addr) { - #error SNTP multiple servers not supported. +#error SNTP multiple servers not supported. } -#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ +#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ static constexpr uint8_t current_server = 0; #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ @@ -117,7 +117,12 @@ struct SNTP { static void start(ip_addr_t address); static void start(const char* ip); - static void start(uint8_t address_head, uint8_t address_second, uint8_t address_third, uint8_t address_last); + static void start( + uint8_t address_head, + uint8_t address_second, + uint8_t address_third, + uint8_t address_last + ); static void stop(void); /* internals */ @@ -131,13 +136,15 @@ struct SNTP { static void retry(void); static void request(void); static void process(const SNTP::Timestamps* timestamps); - static void recv(void *arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port); + + static void + recv(void *arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port); #if !SNTP_SUPPORT_MULTIPLE_SERVERS static constexpr void (*try_next_server)(void) = SNTP::retry; #endif }; // struct SNTP -}; // ST_LIB +}; // namespace ST_LIB #if 0 static constexpr const char* DEFAULT_SERVER_IP = "192.168.0.9"; diff --git a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp index cccaee013..d0356b583 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -14,42 +14,45 @@ #define TRANSFORMATION_FACTOR (SUBSECONDS_PER_SECOND / 999999.0) /* Start offset of the timestamps to extract from the SNTP packet */ -#define SNTP_OFFSET_TIMESTAMPS \ - (SNTP::OFFSET_TRANSMIT_TIME + 8 - sizeof(SNTP::Timestamps)) +#define SNTP_OFFSET_TIMESTAMPS (SNTP::OFFSET_TRANSMIT_TIME + 8 - sizeof(SNTP::Timestamps)) /* Number of seconds between 1970 and Feb 7, 2036 06:28:16 UTC (epoch 1) */ -#define DIFF_SEC_1970_2036 ((u32_t)2085978496L) +#define DIFF_SEC_1970_2036 ((u32_t)2085978496L) -#define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32)) +#define SNTP_FRAC_TO_US(f) ((u32_t)(((u64_t)(f) * 1000000UL) >> 32)) -# define SNTP_GET_SYSTEM_TIME_NTP(s, f) do { \ - u32_t sec_, usec_; \ - SNTP_GET_SYSTEM_TIME(sec_, usec_); \ - (s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \ - (f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \ - } while (0) +#define SNTP_GET_SYSTEM_TIME_NTP(s, f) \ + do { \ + u32_t sec_, usec_; \ + SNTP_GET_SYSTEM_TIME(sec_, usec_); \ + (s) = (s32_t)(sec_ - DIFF_SEC_1970_2036); \ + (f) = usec_ * 4295 - ((usec_ * 2143) >> 16) + 2147; \ + } while (0) #define SNTP_SET_SYSTEM_TIME_US(sec, us) stlib_sntp_set_time((sec), (us)) -#define SNTP_GET_SYSTEM_TIME(sec, us) \ - do { \ - (sec) = stlib_sntp_get_rtc_seconds(); \ - (us) = stlib_sntp_get_rtc_microseconds(); \ +#define SNTP_GET_SYSTEM_TIME(sec, us) \ + do { \ + (sec) = stlib_sntp_get_rtc_seconds(); \ + (us) = stlib_sntp_get_rtc_microseconds(); \ } while (0) -#define SNTP_SET_SYSTEM_TIME_NTP(s, f) \ +#define SNTP_SET_SYSTEM_TIME_NTP(s, f) \ SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f)) namespace ST_LIB { -void SNTP::start(uint8_t address_head, uint8_t address_second, - uint8_t address_third, uint8_t address_last) -{ +void SNTP::start( + uint8_t address_head, + uint8_t address_second, + uint8_t address_third, + uint8_t address_last +) { ip_addr_t address; IP_ADDR4(&address, address_head, address_second, address_third, address_last); SNTP::start(address); } -void SNTP::start(const char *ip) { +void SNTP::start(const char* ip) { IPV4 target(ip); SNTP::start(target.address); } @@ -66,7 +69,7 @@ void SNTP::start(ip_addr_t address) { if (SNTP::opmode == SNTP::MODE) { #if SNTP_STARTUP_DELAY request_task_id = - Scheduler::set_timeout((uint32_t)SNTP_STARTUP_DELAY_FUNC*1000, SNTP::request); + Scheduler::set_timeout((uint32_t)SNTP_STARTUP_DELAY_FUNC * 1000, SNTP::request); #else SNTP::request(); #endif @@ -92,40 +95,37 @@ void SNTP::stop(void) { } } -void SNTP::initialize_request(SNTP::Message *req) +void SNTP::initialize_request(SNTP::Message* req) { memset(req, 0, SNTP::MSG_LEN); - req->li_vn_mode = SNTP::LEAP_INDICATOR_NO_WARNING | - SNTP::VERSION | SNTP::MODE_CLIENT; + req->li_vn_mode = SNTP::LEAP_INDICATOR_NO_WARNING | SNTP::VERSION | SNTP::MODE_CLIENT; -//#if SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP { s32_t secs; uint32_t sec, frac; /* Get the transmit timestamp */ SNTP_GET_SYSTEM_TIME_NTP(secs, frac); - sec = lwip_htonl((uint32_t)secs); + sec = lwip_htonl((uint32_t)secs); frac = lwip_htonl(frac); # if SNTP_CHECK_RESPONSE >= 2 - sntp_last_timestamp_sent.sec = sec; + sntp_last_timestamp_sent.sec = sec; sntp_last_timestamp_sent.frac = frac; # endif req->transmit_timestamp[0] = sec; req->transmit_timestamp[1] = frac; } -//#endif /* SNTP_CHECK_RESPONSE >= 2 || SNTP_COMP_ROUNDTRIP */ } -void SNTP::send_request(const ip_addr_t *server_addr) +void SNTP::send_request(const ip_addr_t* server_addr) { - struct pbuf *p; + struct pbuf* p; LWIP_ASSERT("server_addr != NULL", server_addr != NULL); p = pbuf_alloc(PBUF_TRANSPORT, SNTP::MSG_LEN, PBUF_RAM); if (p != NULL) { - SNTP::Message *sntpmsg = (SNTP::Message*)p->payload; + SNTP::Message* sntpmsg = (SNTP::Message*)p->payload; SNTP::initialize_request(sntpmsg); /* send request */ udp_sendto(SNTP::pcb, p, server_addr, SNTP::PORT); @@ -145,14 +145,13 @@ void SNTP::send_request(const ip_addr_t *server_addr) } else { /* out of memory: set up a timer to send a retry */ SNTP::request_task_id = - Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT*1000, SNTP::request); + Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT * 1000, SNTP::request); } } void SNTP::retry(void) { /* set up a timer to send a retry and increase the retry delay */ - SNTP::request_task_id = - Scheduler::set_timeout(SNTP::retry_timeout*1000, SNTP::request); + SNTP::request_task_id = Scheduler::set_timeout(SNTP::retry_timeout * 1000, SNTP::request); #if SNTP_RETRY_TIMEOUT_EXP { @@ -176,14 +175,18 @@ void SNTP::request(void) { if (SNTP::servers[SNTP::current_server].name) { /* always resolve the name and rely on dns-internal caching & timeout */ ip_addr_set_zero(&SNTP::servers[SNTP::current_server].addr); - err = dns_gethostbyname(SNTP::servers[SNTP::current_server].name, &sntp_server_address, - SNTP::dns_found, NULL); + err = dns_gethostbyname( + SNTP::servers[SNTP::current_server].name, + &sntp_server_address, + SNTP::dns_found, + NULL + ); if (err == ERR_INPROGRESS) { - /* DNS request sent, wait for sntp_dns_found being called */ - return; - } else if (err == ERR_OK) { - SNTP::servers[SNTP::current_server].addr = sntp_server_address; - } + /* DNS request sent, wait for sntp_dns_found being called */ + return; + } else if (err == ERR_OK) { + SNTP::servers[SNTP::current_server].addr = sntp_server_address; + } } else #endif /* SNTP_SERVER_DNS */ { @@ -196,22 +199,22 @@ void SNTP::request(void) { } else { /* address conversion failed, try another server */ SNTP::try_next_server_task_id = - Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT*1000, SNTP::try_next_server); + Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT * 1000, SNTP::try_next_server); } } -void SNTP::process(const SNTP::Timestamps *timestamps) +void SNTP::process(const SNTP::Timestamps* timestamps) { s32_t sec; u32_t frac; - sec = (s32_t)lwip_ntohl(timestamps->xmit.sec); + sec = (s32_t)lwip_ntohl(timestamps->xmit.sec); frac = lwip_ntohl(timestamps->xmit.frac); #if SNTP_COMP_ROUNDTRIP -# if SNTP_CHECK_RESPONSE >= 2 +#if SNTP_CHECK_RESPONSE >= 2 if (timestamps->recv.sec != 0 || timestamps->recv.frac != 0) -# endif +#endif { s32_t dest_sec; u32_t dest_frac; @@ -220,10 +223,10 @@ void SNTP::process(const SNTP::Timestamps *timestamps) /* Get the destination time stamp, i.e. the current system time */ SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac); - step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec) - : ((u32_t)dest_sec - (u32_t)sec); + step_sec = + (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec) : ((u32_t)dest_sec - (u32_t)sec); /* In order to avoid overflows, skip the compensation if the clock step - * is larger than about 34 years. */ + * is larger than about 34 years. */ if ((step_sec >> 30) == 0) { s64_t t1, t2, t3, t4; @@ -234,7 +237,7 @@ void SNTP::process(const SNTP::Timestamps *timestamps) /* Clock offset calculation according to RFC 4330 */ t4 += ((t2 - t1) + (t3 - t4)) / 2; - sec = (s32_t)((u64_t)t4 >> 32); + sec = (s32_t)((u64_t)t4 >> 32); frac = (u32_t)((u64_t)t4); } } @@ -244,7 +247,7 @@ void SNTP::process(const SNTP::Timestamps *timestamps) LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */ } -void SNTP::recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +void SNTP::recv(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port) { SNTP::Timestamps timestamps; uint8_t mode; @@ -259,7 +262,7 @@ void SNTP::recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t /* check server address and port */ if (((SNTP::opmode != SNTP::OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && (port == SNTP::PORT)) -#else /* SNTP_CHECK_RESPONSE >= 1 */ +#else /* SNTP_CHECK_RESPONSE >= 1 */ LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); #endif /* SNTP_CHECK_RESPONSE >= 1 */ @@ -268,7 +271,7 @@ void SNTP::recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t if (p->tot_len == SNTP::MSG_LEN) { mode = pbuf_get_at(p, 0) & SNTP::MODE_MASK; /* if this is a SNTP response... */ - if (((SNTP::opmode == SNTP::OPMODE_POLL) && (mode == SNTP::MODE_SERVER)) || + if (((SNTP::opmode == SNTP::OPMODE_POLL) && (mode == SNTP::MODE_SERVER)) || ((SNTP::opmode == SNTP::OPMODE_LISTENONLY) && (mode == SNTP::MODE_BROADCAST))) { stratum = pbuf_get_at(p, SNTP::OFFSET_STRATUM); @@ -326,8 +329,7 @@ void SNTP::recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t SNTP::retry_timeout = SNTP::RETRY_TIMEOUT; sntp_update_delay = (u32_t)SNTP::UPDATE_DELAY; - SNTP::request_task_id = - Scheduler::set_timeout(sntp_update_delay, SNTP::request); + SNTP::request_task_id = Scheduler::set_timeout(sntp_update_delay, SNTP::request); } } else if (err == SNTP::ERR_KOD) { /* KOD errors are only processed in case of an explicit poll response */ From baaf8da1bef9ee0105bd1dfc84cd162eb53e1efc Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 13:07:39 +0200 Subject: [PATCH 05/12] Add changeset --- .changesets/SNTP-impl.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .changesets/SNTP-impl.md diff --git a/.changesets/SNTP-impl.md b/.changesets/SNTP-impl.md new file mode 100644 index 000000000..92b0301d8 --- /dev/null +++ b/.changesets/SNTP-impl.md @@ -0,0 +1,33 @@ +release: minor +summary: Rework SNTP module in ST-LIB to use ST-LIB scheduler instead of Lwip one + +example usage: + +```cpp +/* ... */ +int main(void) { + MainBoard::init(); + + led_instance = &MainBoard::instance_of(); + auto eth_instance = &MainBoard::instance_of(); + + Scheduler::register_task(200'000, []{ led_instance->toggle(); }); + + ST_LIB::SNTP::start("192.168.0.9"); + + Scheduler::register_task(1'000'000, []{ + RTCData data = Global_RTC::get_rtc_timestamp(); + INFO("RTC: %u; %uyr %umon %uday %uh %umin %us", + data.counter, data.year, data.month, data.day, + data.hour, data.minute, data.second); + }); + + while (1) { + eth_instance->update(); + Scheduler::update(); + Diagnostics::Hub::flush(); + } +} +``` +Led is not needed but it is to show the board is doing work. + From 8b83575de7116c45680448e75582164578e0985c Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 13:13:23 +0200 Subject: [PATCH 06/12] formatting part 3 --- .changesets/SNTP-impl.md | 1 - .../Services/Communication/SNTP/SNTP.hpp | 4 ++- .../Services/Communication/SNTP/SNTP.cpp | 25 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.changesets/SNTP-impl.md b/.changesets/SNTP-impl.md index 92b0301d8..da11df234 100644 --- a/.changesets/SNTP-impl.md +++ b/.changesets/SNTP-impl.md @@ -30,4 +30,3 @@ int main(void) { } ``` Led is not needed but it is to show the board is doing work. - diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index da8e31312..3e6c99d40 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -3,6 +3,8 @@ * * Created on: 21 feb. 2023 * Author: Ricardo + * Edited on: 22 sep. 2026 + * by: Víctor */ #pragma once @@ -138,7 +140,7 @@ struct SNTP { static void process(const SNTP::Timestamps* timestamps); static void - recv(void *arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port); + recv(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port); #if !SNTP_SUPPORT_MULTIPLE_SERVERS static constexpr void (*try_next_server)(void) = SNTP::retry; diff --git a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp index d0356b583..9ee22f39f 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -3,6 +3,8 @@ * * Created on: 21 feb. 2023 * Author: Ricardo + * Edited on: 22 sep. 2026 + * by: Víctor */ #include "HALAL/Services/Communication/SNTP/SNTP.hpp" @@ -31,10 +33,10 @@ #define SNTP_SET_SYSTEM_TIME_US(sec, us) stlib_sntp_set_time((sec), (us)) #define SNTP_GET_SYSTEM_TIME(sec, us) \ - do { \ - (sec) = stlib_sntp_get_rtc_seconds(); \ - (us) = stlib_sntp_get_rtc_microseconds(); \ - } while (0) + do { \ + (sec) = stlib_sntp_get_rtc_seconds(); \ + (us) = stlib_sntp_get_rtc_microseconds(); \ + } while (0) #define SNTP_SET_SYSTEM_TIME_NTP(s, f) \ SNTP_SET_SYSTEM_TIME_US((u32_t)((s) + DIFF_SEC_1970_2036), SNTP_FRAC_TO_US(f)) @@ -95,8 +97,7 @@ void SNTP::stop(void) { } } -void SNTP::initialize_request(SNTP::Message* req) -{ +void SNTP::initialize_request(SNTP::Message* req) { memset(req, 0, SNTP::MSG_LEN); req->li_vn_mode = SNTP::LEAP_INDICATOR_NO_WARNING | SNTP::VERSION | SNTP::MODE_CLIENT; @@ -108,17 +109,16 @@ void SNTP::initialize_request(SNTP::Message* req) sec = lwip_htonl((uint32_t)secs); frac = lwip_htonl(frac); -# if SNTP_CHECK_RESPONSE >= 2 +#if SNTP_CHECK_RESPONSE >= 2 sntp_last_timestamp_sent.sec = sec; sntp_last_timestamp_sent.frac = frac; -# endif +#endif req->transmit_timestamp[0] = sec; req->transmit_timestamp[1] = frac; } } -void SNTP::send_request(const ip_addr_t* server_addr) -{ +void SNTP::send_request(const ip_addr_t* server_addr) { struct pbuf* p; LWIP_ASSERT("server_addr != NULL", server_addr != NULL); @@ -223,7 +223,7 @@ void SNTP::process(const SNTP::Timestamps* timestamps) /* Get the destination time stamp, i.e. the current system time */ SNTP_GET_SYSTEM_TIME_NTP(dest_sec, dest_frac); - step_sec = + step_sec = (dest_sec < sec) ? ((u32_t)sec - (u32_t)dest_sec) : ((u32_t)dest_sec - (u32_t)sec); /* In order to avoid overflows, skip the compensation if the clock step * is larger than about 34 years. */ @@ -247,8 +247,7 @@ void SNTP::process(const SNTP::Timestamps* timestamps) LWIP_UNUSED_ARG(frac); /* might be unused if only seconds are set */ } -void SNTP::recv(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port) -{ +void SNTP::recv(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port) { SNTP::Timestamps timestamps; uint8_t mode; uint8_t stratum; From 797c5284864defa7c522e5bbd12707b10e8a85b1 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 13:15:03 +0200 Subject: [PATCH 07/12] formatting part 4 --- Src/HALAL/Services/Communication/SNTP/SNTP.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp index 9ee22f39f..8d9cc890f 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -203,8 +203,7 @@ void SNTP::request(void) { } } -void SNTP::process(const SNTP::Timestamps* timestamps) -{ +void SNTP::process(const SNTP::Timestamps* timestamps) { s32_t sec; u32_t frac; From 2c7e26ab608330a8b9ed27e28fd62e637649aed3 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 18:53:46 +0200 Subject: [PATCH 08/12] Add a maximum amount of calls to request and recv --- Inc/HALAL/Services/Communication/SNTP/SNTP.hpp | 8 ++++++++ Src/HALAL/Services/Communication/SNTP/SNTP.cpp | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index 3e6c99d40..c0bbbe022 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -26,6 +26,11 @@ struct SNTP { static constexpr uint32_t RECV_TIMEOUT = 15000; static constexpr uint32_t UPDATE_DELAY = 3600000; + /* to have a maximum amount of time SNTP is on for, we use retry_max and recv_max constants */ + + static constexpr uint16_t REQUEST_MAX = 512; + static constexpr uint16_t RECV_MAX = 8; + static constexpr uint8_t OPMODE_POLL = 0; static constexpr uint8_t OPMODE_LISTENONLY = 1; @@ -133,6 +138,9 @@ struct SNTP { static inline uint16_t try_next_server_task_id = Scheduler::INVALID_ID; static inline uint8_t opmode = SNTP::MODE; + static inline uint16_t request_count = 0; + static inline uint16_t recv_count = 0; + static void initialize_request(SNTP::Message* req); static void send_request(const ip_addr_t* server_addr); static void retry(void); diff --git a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp index 8d9cc890f..7af62b82d 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -62,6 +62,9 @@ void SNTP::start(const char* ip) { void SNTP::start(ip_addr_t address) { SNTP::servers[0].addr = address; + SNTP::recv_count = 0; + SNTP::request_count = 0; + if (SNTP::pcb == NULL) { SNTP::pcb = udp_new_ip_type(IPADDR_TYPE_ANY); LWIP_ASSERT("Failed to allocate udp pcb for sntp client", SNTP::pcb != NULL); @@ -95,6 +98,9 @@ void SNTP::stop(void) { udp_remove(SNTP::pcb); SNTP::pcb = NULL; } + + SNTP::request_task_id = Scheduler::INVALID_ID; + SNTP::try_next_server_task_id = Scheduler::INVALID_ID; } void SNTP::initialize_request(SNTP::Message* req) { @@ -201,6 +207,11 @@ void SNTP::request(void) { SNTP::try_next_server_task_id = Scheduler::set_timeout((uint32_t)SNTP::RETRY_TIMEOUT * 1000, SNTP::try_next_server); } + + SNTP::request_count++; + if (SNTP::request_count > SNTP::REQUEST_MAX) { + SNTP::stop(); + } } void SNTP::process(const SNTP::Timestamps* timestamps) { @@ -338,6 +349,11 @@ void SNTP::recv(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* } else { /* ignore any broken packet, poll mode: retry after timeout to avoid flooding */ } + + SNTP::recv_count++; + if (SNTP::recv_count > SNTP::RECV_MAX) { + SNTP::stop(); + } } }; // namespace ST_LIB From 61c7756423f8f06d6126bacbbff266d7be7c6806 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 24 Sep 2026 19:28:41 +0200 Subject: [PATCH 09/12] Add some documentation for SNTP --- docs/communications/SNTP.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/communications/SNTP.md diff --git a/docs/communications/SNTP.md b/docs/communications/SNTP.md new file mode 100644 index 000000000..3a196c9d7 --- /dev/null +++ b/docs/communications/SNTP.md @@ -0,0 +1,19 @@ +# SNTP module in ST-LIB + +The SNTP module has been reworked to use the ST-LIB scheduler instead of the Lwip scheduler. It will use a single task in the scheduler at most. + +After starting SNTP with `SNTP::start(...)` it will retry at maximum 512 times and when it gets a valid response it will process a maximum of 8 responses and after it will call `SNTP::stop()` internally. + +If you need to use SNTP again for whatever reason after it stops automatically, call `SNTP::start(...)` again and it will reset the counters for retry and response. + +```cpp +static void start(ip_addr_t address); +static void start(const char* ip); +static void start( + uint8_t address_head, + uint8_t address_second, + uint8_t address_third, + uint8_t address_last +); +static void stop(void); +``` From 142c0e7d5a14abb2adc606f9041d38236c2cc998 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 25 Sep 2026 08:10:51 +0200 Subject: [PATCH 10/12] Add configurable STLIB_SNTP_PORT --- Inc/HALAL/Services/Communication/SNTP/SNTP.hpp | 7 ++++++- docs/communications/SNTP.md | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index c0bbbe022..f79f179c3 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -15,12 +15,17 @@ #include "C++Utilities/CppUtils.hpp" #include "HALAL/Services/Time/Scheduler.hpp" +#ifndef STLIB_SNTP_PORT +/* default port is 8123 */ +# define STLIB_SNTP_PORT 8123 +#endif + namespace ST_LIB { struct SNTP { /* config values for SNTP */ - static constexpr uint16_t PORT = 8123; + static constexpr uint16_t PORT = STLIB_SNTP_PORT; static constexpr uint8_t MAX_SERVERS = 1; static constexpr uint32_t RETRY_TIMEOUT = 15000; static constexpr uint32_t RECV_TIMEOUT = 15000; diff --git a/docs/communications/SNTP.md b/docs/communications/SNTP.md index 3a196c9d7..03860d2db 100644 --- a/docs/communications/SNTP.md +++ b/docs/communications/SNTP.md @@ -6,6 +6,8 @@ After starting SNTP with `SNTP::start(...)` it will retry at maximum 512 times a If you need to use SNTP again for whatever reason after it stops automatically, call `SNTP::start(...)` again and it will reset the counters for retry and response. +To change the SNTP port, `#define` STLIB_SNTP_PORT **before** `#include "ST-LIB.hpp"` + ```cpp static void start(ip_addr_t address); static void start(const char* ip); From 8248541e4e57b8d67a8551314389d7a11d82ecf9 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 25 Sep 2026 08:12:32 +0200 Subject: [PATCH 11/12] formatting --- Inc/HALAL/Services/Communication/SNTP/SNTP.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index f79f179c3..77ac6a056 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -17,7 +17,7 @@ #ifndef STLIB_SNTP_PORT /* default port is 8123 */ -# define STLIB_SNTP_PORT 8123 +#define STLIB_SNTP_PORT 8123 #endif namespace ST_LIB { From 39551ee0d19f9dde95fb34085955bfee2961c904 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 25 Sep 2026 17:27:55 +0200 Subject: [PATCH 12/12] Add a couple lines of documentation to start and stop --- .../Services/Communication/SNTP/SNTP.hpp | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index 77ac6a056..84ecaff72 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -36,6 +36,29 @@ struct SNTP { static constexpr uint16_t REQUEST_MAX = 512; static constexpr uint16_t RECV_MAX = 8; + /* start SNTP, will stop after REQUEST_MAX requests or + * RECV_MAX replies from the server + */ + static void start(ip_addr_t address); + /* start SNTP, will stop after REQUEST_MAX requests or + * RECV_MAX replies from the server + */ + static void start(const char* ip); + /* start SNTP, will stop after REQUEST_MAX requests or + * RECV_MAX replies from the server + */ + static void start( + uint8_t address_head, + uint8_t address_second, + uint8_t address_third, + uint8_t address_last + ); + + /* manually stop STNP */ + static void stop(void); + + /* SNTP enum values */ + static constexpr uint8_t OPMODE_POLL = 0; static constexpr uint8_t OPMODE_LISTENONLY = 1; @@ -127,16 +150,6 @@ struct SNTP { static inline struct udp_pcb* pcb; static inline uint32_t retry_timeout = SNTP::RETRY_TIMEOUT; - static void start(ip_addr_t address); - static void start(const char* ip); - static void start( - uint8_t address_head, - uint8_t address_second, - uint8_t address_third, - uint8_t address_last - ); - static void stop(void); - /* internals */ static inline uint16_t request_task_id = Scheduler::INVALID_ID;