In the Internet of Things world and especially when we are going to protect the data transmitted by an embedded system from prying eyes through encryption algorithms (AES, DES, 3DES, RSA, ...) and with related network protocols (SSL, TLS , DTLS, ...), correct date/time on our board plays a fundamental role.
In fact, the encryption algorithms are strongly based on Pseudor-Random Number Generators (PRNG), which often needs to use the current date/time as a "seed" of the generation. Being pseudo-random generators and not real generators, it is important that for each system boot the "seed" is different otherwise the generated sequence is the same as the earlier boot and therefore predictable.
Furthermore, in case we have to access a service in the cloud for which a token authentication is required (eg. SAS, Shared Access Signature, on Microsoft Azure Service Bus), it is important that the request also contains a expiry timestamp based of the token (eg. in the case of a SWT, Simple Web Toke); the timestamp is obviously calculated to suit your needs and related to a correct date/time in the system.
The ways in which you can set up and update the date/time in an embedded system are typically two :
In the first case, the RTC has the task of saving and provide the system with the updated date/time even with subsequent reboots; in the second case, the system connects to the server to get a date/time but without having the opportunity to meet with the correct information at the next reboot.
Obviously the two modes can also be used together: the first time the system is synchronized with a (S)NTP server and saves the date/time on the RTC. On the next boot, the system may ask to the RTC (equipped with a lithium battery) the date/time without the need for a connection to the (S)NTP server. At any time, you may require synchronization with the server to update the RTC locally.
Developing with the .NET Framework, we get the date/time using the DateTime.Now property; if we try to execute this operation at startup on a board with the .Net Micro Framework we haven’t certainly the correct date and time !!
The use of an RTC is not provided natively by the framework, but fortunately it provides the TimeService class that helps us in the use of a (S)NTP server.
This class provides a set of properties, methods and events which are :
Above, only a minimal part of all TimeService features.
The static TimeService class exposes all settings through the Settings property which contains some properties for the settings (of course).
To set them, we can try to use the following code
1: TimeService.Settings.RefreshTime = 10;
2: TimeService.Settings.ForceSyncAtWakeUp = true;
The default values for RefreshTIme and ForceSyncAtWakeUp are 50000 and false. If we execute the above code, we can see that after the instructions, the properties have the same values and aren’t changed to 10 and true !! Why ?
The reason for this behavior is the native implementation of the "get" for Settings property. In the source code of the .Net Micro Framework we can find it :
1: HRESULT Library_spot_Time_native_Microsoft_SPOT_Time_TimeService::get_Settings___STATIC__MicrosoftSPOTTimeTimeServiceSettings( CLR_RT_StackFrame& stack )
2: {
3: TINYCLR_HEADER();
4:
5: TimeService_Settings settings;
6: CLR_RT_HeapBlock& top = stack.PushValueAndClear();
7: CLR_RT_HeapBlock* managedSettings = NULL;
8:
9: TINYCLR_CHECK_HRESULT(TimeService_LoadSettings(&settings));
10:
11: TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex( top, g_CLR_RT_WellKnownTypes.m_TimeServiceSettings ));
12: managedSettings = top.Dereference();
13:
14: managedSettings.SetInteger( settings.PrimaryServerIP );
15: managedSettings.SetInteger( settings.AlternateServerIP );
16: managedSettings.SetInteger( settings.RefreshTime );
17: managedSettings.SetInteger( settings.Tolerance );
18: managedSettings.SetBoolean( 0 != (settings.Flags & TimeService_Settings_Flags_ForceSyncAtWakeUp) );
19: managedSettings.SetBoolean( 0 != (settings.Flags & TimeService_Settings_Flags_AutoDST) );
20:
21: TINYCLR_NOCLEANUP();
22: }
As we can see, the function creates a local “settings” variable and load all current settings inside it. It copies the “settings” fields inside a managed variable returned to our code (using the stack and by reference) … so we don’t set the global settings of TimeService class but a copy of a local native function ! I don’t know if it is a bug or the real behavior but to define the settings in the proper way we need to create a new instance of TimeServiceSettings class and assign it to the Settings property of TimeService class.
1: TimeServiceSettings settings = new TimeServiceSettings();
2: settings.RefreshTime = 10; // every 10 seconds
3: settings.ForceSyncAtWakeUp = true;
4: TimeService.Settings = settings;
Ultimately, in order to use correctly the TimeService class, we can use the following code
1: void ethernetJ11D_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
3: TimeServiceSettings settings = new TimeServiceSettings();
4: settings.RefreshTime = 10; // every 10 seconds
5: settings.ForceSyncAtWakeUp = true;
6:
7: TimeService.SystemTimeChanged += TimeService_SystemTimeChanged;
8: TimeService.TimeSyncFailed += TimeService_TimeSyncFailed;
9: TimeService.SetTimeZoneOffset(60);
11: IPHostEntry hostEntry = Dns.GetHostEntry("time.nist.gov");
12: IPAddress address = hostEntry.AddressList;
13: if (address != null)
14: settings.PrimaryServer = address[0].GetAddressBytes();
15:
16: hostEntry = Dns.GetHostEntry("time.windows.com");
17: address = hostEntry.AddressList;
18: if (address != null)
19: settings.AlternateServer = address[0].GetAddressBytes();
21: TimeService.Settings = settings;
22:
23: TimeService.Start();
24: }
25:
26: void TimeService_TimeSyncFailed(object sender, TimeSyncFailedEventArgs e)
27: {
28: Debug.Print("DateTime Sync Failed");
29: }
30:
31: void TimeService_SystemTimeChanged(object sender, SystemTimeChangedEventArgs e)
32: {
33: Debug.Print("DateTime = " + DateTime.Now.ToString());
34: }
Based on the time set in RefreshTime, the SystemTimeChanged event will be raised periodically and we could be assured that the DateTime.Now property will be properly synchronized with the server.
View this page in another language: