Synchronize the Clock with a Reference Server on the Internet (English)

by Marco Minerva (translated from Italian by Mike Dodaro)

Nearly all applications have to use date and time to record when files are saved, to record accesses to resources, etc. The .NET Micro Framework is no exception.  If it were, every application, hardly under way, would have to update its own clock to synchonize it with the real timetable.

Beginning with version 4,0, the .NET Micro Framework contains an appropriate class, TimeService, with which it is possible synchronize the inner clock by a reference server on the Internet, called NTP Server, as we will see by using it.

For our example, we will use the GHI Electronics modules Display_T35 and Ethernet.  We must add to the project a reference to the Microsoft.SPOT.Time assembly, which contains the definition of the TimeService class.  In the ProgramStarted method we insert the initialization of objects:

private DispatcherTimer timer;
private static bool timeSynchronized;

void ProgramStarted()
{
    ethernet.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkUp);
    ethernet.NetworkDown += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkDown);
    ethernet.UseDHCP();

    TimeService.SystemTimeChanged += new SystemTimeChangedEventHandler(TimeService_SystemTimeChanged);
    TimeService.TimeSyncFailed += new TimeSyncFailedEventHandler(TimeService_TimeSyncFailed);

    timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond * 500);
    timer.Tick += new EventHandler(timer_Tick);

    SetupWindow();
    Debug.Print("Program Started");
}

We set the events of the NetworkModule interface and use DHCP.  Next, we set the events that the TimeService object generates, when the system time is synchronized with a server on the Internet, and when there is an error during synchronization. In the example we also define a DispatcherTimer that will update the video timetable.  Finally, we recall the SetupWindow routine, that now defines a text case that will be updated with the date values, as shown in the following code block.

private void SetupWindow()
{
    Window window = display.WPFWindow;
    Font baseFont = Resources.GetFont(Resources.FontResources.NinaB);

    Canvas canvas = new Canvas();
    window.Child = canvas;

    txtDateTime = new Text(baseFont, "Waiting for time update...");
    canvas.Children.Add(txtDateTime);
    Canvas.SetTop(txtDateTime, 100);
    Canvas.SetLeft(txtDateTime, 90);
}

The real synchronization is carried out during the initialization of the NetworkModule interface, that is, when the NetworkUp event is generated:

private void ethernet_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
{
    Debug.Print("Network up!");

    // Configure TimeService settings.
    TimeServiceSettings settings = new TimeServiceSettings();
    settings.ForceSyncAtWakeUp = true;
    settings.RefreshTime = 1800;    // in seconds.

    IPAddress[] address = Dns.GetHostEntry("time-a.nist.gov").AddressList;
    if (address != null && address.Length > 0)
        settings.PrimaryServer = address[0].GetAddressBytes();

    address = Dns.GetHostEntry("pool.ntp.org").AddressList;
    if (address != null && address.Length > 0)
        settings.AlternateServer = address[0].GetAddressBytes();

    TimeService.Settings = settings;

    // Add the time zone offset to the retrieved UTC Time (in this example, it assumes that
    // time zone is GMT+1).
    TimeService.SetTimeZoneOffset(60);

    TimeService.Start();
    timer.Start();
}

private static void TimeService_TimeSyncFailed(object sender, TimeSyncFailedEventArgs e)
{
    Debug.Print("Error synchronizing system time with NTP server: " + e.ErrorCode);
}

private static void TimeService_SystemTimeChanged(object sender, SystemTimeChangedEventArgs e)
{
    Debug.Print("Network time received.");
    if (!timeSynchronized)
        timeSynchronized = true;
}

private void timer_Tick(object sender, EventArgs e)
{
    if (timeSynchronized)
        txtDateTime.TextContent = DateTime.Now.ToString();
}

We define an object of type TimeServiceSettings, and we use it to set up the properties of the synchronization.  In particular, we can specify two servers, in our example time-a.nist.gov and pool.ntp.org. When synchronization of the timetable is required, TimeService first tries to connect to the PrimaryServer; if the connection fails, a second attempt is made to the AlternateServer.

The recovered timetable is in UTC format. In the code we suppose a lag GMT+1, therefore recalling the TimeService.SetTimeZoneOffset method we tell the service to add 60 minutes automatically to the recovered timetable.

At last, with the method Start we start the real recovery: the system will try to recover the specific timetable being connected to the server and will launch the associated events. The call to the server is repeated at specified intervals equal to the number of seconds in the RefreshTime property.  But, at any moment, it is possible to use the TimeService.UpdateNow method in order to force the immediate update. The last rouine introduced in the example takes care to update the table visualized on the screen.

In conclusion, complete the Program.cs file of our application is as follows:

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Microsoft.SPOT.Time;
using System.Net;

namespace TimeServiceExample
{
    public partial class Program
    {
        private DispatcherTimer timer;
        private static bool timeSynchronized;

        void ProgramStarted()
        {
            ethernet.NetworkUp +=
				new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkUp);
            ethernet.NetworkDown +=
				new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkDown);
            ethernet.UseDHCP();

            TimeService.SystemTimeChanged +=
				new SystemTimeChangedEventHandler(TimeService_SystemTimeChanged);
            TimeService.TimeSyncFailed +=
				new TimeSyncFailedEventHandler(TimeService_TimeSyncFailed);

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond * 500);
            timer.Tick += new EventHandler(timer_Tick);

            SetupWindow();
            Debug.Print("Program Started");
        }

        private Text txtDateTime;

        private void SetupWindow()
        {
            Window window = display.WPFWindow;
            Font baseFont = Resources.GetFont(Resources.FontResources.NinaB);

            Canvas canvas = new Canvas();
            window.Child = canvas;

            txtDateTime = new Text(baseFont, "Waiting for time update...");
            canvas.Children.Add(txtDateTime);
            Canvas.SetTop(txtDateTime, 100);
            Canvas.SetLeft(txtDateTime, 90);
        }

        private void ethernet_NetworkDown(GTM.Module.NetworkModule sender,
									GTM.Module.NetworkModule.NetworkState state)
        {
            Debug.Print("Network down!");
        }

        private void ethernet_NetworkUp(GTM.Module.NetworkModule sender,
									GTM.Module.NetworkModule.NetworkState state)
        {
            Debug.Print("Network up!");

            // Configure TimeService settings.
            TimeServiceSettings settings = new TimeServiceSettings();
            settings.ForceSyncAtWakeUp = true;
            settings.RefreshTime = 1800;    // in seconds.

            IPAddress[] address = Dns.GetHostEntry("time-a.nist.gov").AddressList;
            if (address != null && address.Length > 0)
                settings.PrimaryServer = address[0].GetAddressBytes();

            address = Dns.GetHostEntry("pool.ntp.org").AddressList;
            if (address != null && address.Length > 0)
                settings.AlternateServer = address[0].GetAddressBytes();

            TimeService.Settings = settings;

            // Add the time zone offset to the retrieved UTC Time (in this example, it assumes that
            // time zone is GMT+1).
            TimeService.SetTimeZoneOffset(60);

            TimeService.Start();
            timer.Start();
        }

        private static void TimeService_TimeSyncFailed(object sender, TimeSyncFailedEventArgs e)
        {
            Debug.Print("Error synchronizing system time with NTP server: " + e.ErrorCode);
        }

        private static void TimeService_SystemTimeChanged(object sender, SystemTimeChangedEventArgs e)
        {
            Debug.Print("Network time received.");
            if (!timeSynchronized)
                timeSynchronized = true;
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (timeSynchronized)
                txtDateTime.TextContent = DateTime.Now.ToString();
        }
    }
}

In order to complete the code, we will have to add the management of standard time, which we will do in one of the next posts.

This example application is available for download.

TimeServiceExample.zip

About these ads

,

  1. #1 by David De Sloovere (@DavidDeSloovere) on September 21, 2012 - 12:48 PM

    Thanks for sharing the code.
    I’m not quite there yet, but will save me some time in a few weeks.

  1. Gadgeteer Home Automation System « Integral Design
  2. TaW: Week 9 – Gadgeteer Temperature Logger | jedibowler.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: