Overview

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.

SNTP API

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);

The function 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.

The function 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.

Example

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 my_time().

  • 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://8.8.8.8: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 216.239.35.12
    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.

The function mg_millis() returns the current uptime in milliseconds; we just add our running time (in seconds) to our boot timestamp to get current time.

Browse latest code