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.

 

RTC and (S) NTP server

 

The ways in which you can set up and update the date/time in an embedded system are typically two :

 

  • RTC (Real Time Clock) that can be inside the microcontroller itself or an external device connected to it with a suitable protocol (in many cases I2C);
  • Connection to an (S)NTP server (Simple Network Time Protocol) and its synchronization with the latter with a certain rate or at the express request;

 

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.

 

TimeService and .Net Micro Framework

 

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 :

 

  • Settings: propertiy (type TimeServiceSettings) that allows you to define the main service settings (primary and alternate server to connect for synchronization, refresh interval, forced synchronization at every boot, ...);
  • SystemTimeChanged and TimeSyncFailed: events respectively raised when the date and time are changed as a result of a correct synchronization, or when the synchronization has failed (eg. no connection);
  • SetTimeZoneOffset : method for setting the offset related to the UTC/GMT time for our zone;
  • Start/Stop : methods for starting and stopping the synchronization service;
  • UpdateNow : method to force an immediate syncronization;

 

Above, only a minimal part of all TimeService features.

 

Strange settings anomaly : a step into native code

 

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 ?

 

TimeServiceSettings

 

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;

 

A complete example

 

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)
   2: {
   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);
  10:  
  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();
  20:         
  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.

It's important to say that the TimeService class is based on a piece of native code that is included in the firmware of the GHI Electronics boards (FEZ Spider, FEZ Raptor, ...) but not in the firmware of the Netduino board, for which you need the use of a third party class that implements an (S)NTP client.