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:
- direct RTC update from receiving the NTP time packet
- optionally support more than one NTP server
- the IP address of the NTP server(s) stored in a local file
- timeout error recovery should the NTP server(s) not be available. No RTC update should the NTP access fail
- allow for a UTC offset, also stored in the local file
- DST correction
- use DNS for NTP servers IP address resolution
- periodic updates at specified time intervals
- 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.
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:
Note: LWIP/sntp has a memory leak in this version.
Here's rev.2 of the program:
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:
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.
You need to log in to post a comment
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?