SNTP Client

MBED clock has to be set somehow in order for the RTC to be useful. At a minimum, set_time(...) has to be called with some fixed value, but then all time() readings are not realtime. To set current time a user interface has to be provided, which may be not a viable option (need buttons, LCD screen). A better approach is to use NTP (or Simple NTP) to retrieve time from one of time servers on the Internet (given that MBED is connected to a network with Internet gateway).

HTTPClient/HTTPServer cookbook uses LWIP. There is a contributed app code in the LWIP repository that implements SNTP. Using that code together with HTTPClient/HTTPServer makes a functional SNTP client. It is a simplified NTP which is precise only within 30ms or so. It should be enough for pretty much any MBED application that I can think of. Besides, time() function returns time_t which is precise to only 1 second.

Kevin Braun summarized desired features pretty well, with three more added by me:

  1. direct RTC update from receiving the NTP time packet
  2. optionally support more than one NTP server
  3. the IP address of the NTP server(s) stored in a local file
  4. timeout error recovery should the NTP server(s) not be available.  No RTC update should the NTP access fail
  5. allow for a UTC offset, also stored in the local file
  6. DST correction
  7. use DNS for NTP servers IP address resolution
  8. periodic updates at specified time intervals
  9. choice of UTC or local time for the RTC

 

All these features can be implemented based on LWIP/sntp.

However, there is a caveat. LWIP is compiled in MBED with NO_SYS = 1, which defines as empty timeout functions sys_timeout/sys_untimeout which are required for timeouts, retries and periodic updates to work. These functions can be plugged in with mbed's timeout. Without it, sntp does only one NTP query.

With plugged timeout/untimeout functions SNTP runs and periodically updates the RTC.

UPDATE 1/2/2010
I'm pretty much done with the majority of the wrapper code which I called SNTPClient. I considered doing it in a class, but given that this class should be a singleton and I never liked C++ singleton pattern, I instead implemented it in a function-based API. If anyone has any ideas how the interface could look and be a singleton, please chime in here.

Another discussion I want to open is about how people want to see DST done. Thinking about it and reading opinions online I realized that there is a need for a database and rules-driven DST algorithm. Ideal solution in my mind would be an Internet service similar to NTP, but for DST rules in different locales. Doing any fixed solution in the library will make the code prone to quick obsolescence from changes to DST rules in any part of the world, which is happening quite often. What I think would be useful is to provide hooks in the SNTPClient library for DST manipulations. Then everyone can pick a strategy that works best for them. To be honest, I think SNTPCLient is not even the best place to do it from, instead some kind of alarm service is needed, similar to timeout. Alarm service will allow setting a callback to be called upon [first opportunity after] predetermined point in time. That point of time is the DST start and stop times. Unfortunately alarm service is out of scope of SNTPClient, so I have to leave DST function incomplete.

SNTPClient looks for a file named "sntp.ini" either on LocalFileSystem, or on SDCard (it is done in main()). If found, it loads it. The file should look like this (note that it is very case-sensitive):

 

# Sample SNTP Configuration file (Section names and variables are case-sensitive)

[Servers]
pool.ntp.org
north-america.pool.ntp.org
time-a.nist.gov
time-b.nist.gov
 
[Global]
RtcUtc=1

Timezone=-8.0
# in hours

DstZone=1
# DST_USA

UpdateDelay=600
RecvTimeout=5
# in seconds

Number of allowed servers is fixed, but it can be changed - it is set by number of entries in SNTP_SERVER_ADDRESS in lwip/Core/lwipopts.h file. UpdateDelay currently limits at 4294 seconds due to internal use of 32-bit microsecond value.

 

Here's the first version of the program:

pub_iva2k_ethsntp

Note: LWIP/sntp has a memory leak in this version.

 

Here's rev.2 of the program:

pub_iva2k_ethsntp

It fixes SNTP memory leak bug, and adds a big chunk of DST rules code. Look into lwip/SNTPClient/DstZones.h to add your DST zone. Share your DST lines in comments here!

 

Here's rev.3 of the program:

pub_iva2k_ethsntp

It changes timeout values to be in seconds. This should allow to have more than 35 minutes between updates. Make sure to edit the sntp.ini file and change UpdateDelay, RecvTimeout to seconds.


6 comments

01 Jan 2010

This looks very interesting and useful, its almost impossible to keep the RTC ticking. Even with a coin cell battery, if you move it just alittle the RTC is reset. How fast is the process from reset to the RTC set? Can you publish a program please?

01 Jan 2010

I'm working on publishable program, so be patient.

I observe very quick response from NTP server. It is basically 2 UDP packets exchanged. Given that precision is said to be around 30ms, I would expect that it is the round-about time. Of course if the network is congested, the packet may get lost. Then retries kick in, and they are on the order of 15 seconds (it is compile-time programmable now).

03 Jan 2010

Great work! Thanks for your reply, im looking forward to it.

03 Jan 2010

Wow looks great! I am going to wire this up to my LCD base and let you know the results.

03 Jan 2010

Thanks again Llya for the very interesting stuff you publish. I've read K&R cover to cover last week (to get C stuff back in order into my mind) and just started C++ self teaching this weekend.

04 Jun 2010

Hello Ilya:

Very cool. I was looking for a simple NTP client to set the RTC when I ran onto your code. Your code certainly provides a wealth of info on setting up more complex HTTP server function including use of RPC.

Thanks for the great example.

Doug Wendelboe


You need to log in to post a comment