diff --git a/.changesets/SNTP-impl.md b/.changesets/SNTP-impl.md new file mode 100644 index 000000000..da11df234 --- /dev/null +++ b/.changesets/SNTP-impl.md @@ -0,0 +1,32 @@ +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. 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..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); } }; diff --git a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp index a87592016..84ecaff72 100644 --- a/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp +++ b/Inc/HALAL/Services/Communication/SNTP/SNTP.hpp @@ -3,24 +3,177 @@ * * Created on: 21 feb. 2023 * Author: Ricardo + * Edited on: 22 sep. 2026 + * by: Víctor */ #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"; +#ifndef STLIB_SNTP_PORT +/* default port is 8123 */ +#define STLIB_SNTP_PORT 8123 +#endif - static void sntp_update( +namespace ST_LIB { + +struct SNTP { + /* config values for SNTP */ + + 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; + 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; + + /* 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 ); - static void sntp_update(string ip); - static void sntp_update(); -}; + + /* manually stop STNP */ + static void stop(void); + + /* SNTP enum values */ + + 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; + + /* 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 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); + 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 +}; // namespace 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..7af62b82d 100644 --- a/Src/HALAL/Services/Communication/SNTP/SNTP.cpp +++ b/Src/HALAL/Services/Communication/SNTP/SNTP.cpp @@ -3,29 +3,47 @@ * * Created on: 21 feb. 2023 * Author: Ricardo + * Edited on: 22 sep. 2026 + * by: Víctor */ #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)) + +#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) -} // namespace +#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) -void SNTP::sntp_update( +#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, @@ -33,15 +51,312 @@ void SNTP::sntp_update( ) { 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; + + 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); + 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; + } + + SNTP::request_task_id = Scheduler::INVALID_ID; + SNTP::try_next_server_task_id = Scheduler::INVALID_ID; +} + +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; + + { + 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; + } +} + +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::sntp_update(string ip) { - IPV4 target(ip.c_str()); - configure_sntp_server(target.address); +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); + } + + SNTP::request_count++; + if (SNTP::request_count > SNTP::REQUEST_MAX) { + SNTP::stop(); + } +} + +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 */ + } + + SNTP::recv_count++; + if (SNTP::recv_count > SNTP::RECV_MAX) { + SNTP::stop(); + } } -void SNTP::sntp_update() { sntp_update(DEFAULT_SERVER_IP); } +}; // namespace ST_LIB extern "C" void stlib_sntp_set_rtc( uint16_t counter, @@ -55,7 +370,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 +385,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; } diff --git a/docs/communications/SNTP.md b/docs/communications/SNTP.md new file mode 100644 index 000000000..03860d2db --- /dev/null +++ b/docs/communications/SNTP.md @@ -0,0 +1,21 @@ +# 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. + +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); +static void start( + uint8_t address_head, + uint8_t address_second, + uint8_t address_third, + uint8_t address_last +); +static void stop(void); +```