This tutorial will show you how to synchronize time with a remote SNTP server.
Potential use cases are:
- Providing a real-time clock for embedded systems without one
- Improving the precision and stability of such a clock
- Providing a time reference for TLS in embedded systems without a clock.
Our actions will be:
- We first write a callback function to handle the results of the call to the SNTP client function. This function will perform the required task to handle the time reference in our system
- Since we need to perform this synchronization periodically, we then write a timer callback function to call the SNTP client. You can check the timers tutorial for more information on using timers
- Finally, after initializing an event manager, we add the timer callback function to the event manager's timer list
The timer callback function will be called by the event manager once the specified time has elapsed, this, in turn, will call the SNTP client. Once the SNTP client has finished, the event manager will call our callback function to handle system time.
When using a TLS library such as mbed-TLS, a working
time() function is required. Other parts of the system might also want to make good use of a call to get the system time, so we provide it.
The SNTP client API is really tiny and consists of just two functions:
struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fn_data); void mg_sntp_request(struct mg_connection *c);
mg_sntp_connect() tries to connect to the SNTP server whose domain name is specified in parameter url, returning a connection handler or NULL on failure. The function specified in parameter fn will be our callback function, and parameter fn_data will be its argument.
mg_sntp_request() performs the action of sending the time request to the SNTP server. The event manager will in turn call our callback function with the result of this action.
For detailed information, see the documentation.
This example sets a periodic timer callback function that queries an SNTP server. The time information so obtained is internally saved in order to be served by a call to the function
- If you've not already done so, clone the Mongoose Library repo
$ git clone https://github.com/cesanta/mongoose
- Build the example, this will also start Mongoose:
$ cd mongoose/examples/sntp-time-sync $ make clean all
- Observe the log
18129c6ae90 3 net.c:183:mg_connect 1 -1 udp://time.google.com:123 18129c6ae90 3 net.c:183:mg_connect 2 -1 udp://220.127.116.11:53 18129c6ae90 3 sock.c:167:mg_send 2 0x3 0:0 33 err 0 (Success) 18129c6ae90 1 sntp.c:51:mg_sntp_request 1 wait until resolved 18129c6ae99 3 sock.c:292:read_conn 2 0x3 0:0 97 err 0 (Success) 18129c6ae99 3 dns.c:167:dns_cb 1 time.google.com is 18.104.22.168 18129c6ae99 3 sock.c:167:mg_send 1 0x4 0:0 48 err 0 (Success) 18129c6af18 3 sock.c:292:read_conn 1 0x4 0:0 48 err 0 (Success) 18129c6af18 2 main.c:29:sfn Got SNTP time: 1654263295276 ms from epoch
What this example does is:
write a SNTP client callback function that receives the results, logs the time, and performs the time synchronization. It may get one of these events of interest:
- MG_EV_SNTP_TIME: valid server response, we take the current time information from the server and subtract our uptime to get our boot timestamp
- MG_EV_CLOSE: connection closed, clean up
write a timer callback function that queries the SNTP server via the SNTP client API:
initialize the event manager, add the timer callback, and call the event manager in an infinite loop:The timer will fire every 5 seconds for demo purposes, you might want to extend this time for production code.
The function to serve the time is the following:
In case it is going to be used with mbedTLS on an embedded system, rename it to
time(), or work your way on its platform macros.
mg_millis() returns the current uptime in milliseconds; we just add our running time (in seconds) to our boot timestamp to get current time.