Updating date and time with ntp?

HomeForumsMonoBrick EV3 FirmwareUpdating date and time with ntp?

This topic contains 2 replies, has 2 voices, and was last updated by Author Image Anders Søborg 2 years, 3 months ago.

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #5329
    Author Image
    Kristofer Jaxne
    Participant

    I wonder if its possible somehow to update the internal time with correct UTC using some ntp server? I can’t find any services in the Linux software so I don’t know how to solve it. I have seen examples for how to let a C# program do the job, but its little to complex when Linux should have support for automatic update. Have anyone get it working?

    #5333
    Author Image
    Kristofer Jaxne
    Participant

    I found solutions to this problem so I can show how I did.

    First I create a new class with the needed methods.

    using System;
    using MonoBrickFirmware;
    using System.Threading;
    using System.Diagnostics;
    using System.Net;
    using System.Net.Sockets;
    using MonoBrickFirmware.Display;
    
    public class Linux
    {
    public Linux ()
    {
    }
    
    public void SendCommand (string file, string arguments)
    {
    	Process proc = new Process ();
    	proc.StartInfo.FileName = file;
    	proc.StartInfo.Arguments = arguments;
    	proc.StartInfo.UseShellExecute = false; 
    	proc.StartInfo.RedirectStandardError = true;
    	proc.StartInfo.RedirectStandardInput = true;
    	proc.StartInfo.RedirectStandardOutput = true;
    	proc.Start();
    	var output = proc.StandardOutput.ReadToEnd ();
    	LcdConsole.WriteLine("stdout: {0}", output);
    }
    
    public DateTime GetNetworkTime()
    {
    	try 
    	{
    		//default Windows time server
    		const string ntpServer = "time.windows.com";
    
    		// NTP message size - 16 bytes of the digest (RFC 2030)
    		var ntpData = new byte[48];
    
    		//Setting the Leap Indicator, Version Number and Mode values
    		ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
    
    		var addresses = Dns.GetHostEntry(ntpServer).AddressList;
    
    		//The UDP port number assigned to NTP is 123
    		var ipEndPoint = new IPEndPoint(addresses[0], 123);
    		//NTP uses UDP
    		var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    
    		socket.Connect(ipEndPoint);
    
    		//Stops code hang if NTP is blocked
    		socket.ReceiveTimeout = 3000;     
    
    		socket.Send(ntpData);
    		socket.Receive(ntpData);
    		socket.Close();
    
    		//Offset to get to the "Transmit Timestamp" field (time at which the reply 
    		//departed the server for the client, in 64-bit timestamp format."
    		const byte serverReplyTime = 40;
    
    		//Get the seconds part
    		ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
    		//Get the seconds fraction
    		ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
    
    		//Convert From big-endian to little-endian
    		intPart = SwapEndianness(intPart);
    		fractPart = SwapEndianness(fractPart);
    
    		var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
    
    		//**UTC** time
    		var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
    
    		networkDateTime = networkDateTime.AddHours(2); // Local time Sweden summer time = UTC + 2
    		return networkDateTime.ToLocalTime();
    
    	}
    	catch 
    	{
    		DateTime time = new DateTime (1900, 01, 01);
    		return time;
    	}
    }
    
    private static uint SwapEndianness(ulong x)
    {
    	return (uint) (((x & 0x000000ff) << 24) +
    		((x & 0x0000ff00) << 8) +
    		((x & 0x00ff0000) >> 8) +
    		((x & 0xff000000) >> 24));
    }
    }

    I use the methods in the class like this:

    Linux linux = new Linux ();
    DateTime servertime = new DateTime();
    
    for (int i = 0; i < 5; i++)
    {
            servertime = linux.GetNetworkTime ();
    	Thread.Sleep (500);
    	if (servertime.Year != 1900)
    		break;
    }
    if (servertime.Year == 1900) 
    	LcdConsole.WriteLine ("Failed to get time");
    else
    	LcdConsole.WriteLine (servertime.ToString ("yyyy-MM-dd HH:mm:ss"));
    			
    linux.SendCommand ("date", "\"" + servertime.ToString ("yyyy-MM-dd HH:mm:ss") + "\"");
    linux.SendCommand ("hwclock", "-w -l");
    #5335
    Author Image
    Anders Søborg
    Key Master

    Hi there

    Nice job. Thanks a lot for sharing. I guess that a lot of other people will benefit from this.

    /Anders

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.

Posted in

Make a donation