Синхронизация времени узла

<< Click to Display Table of Contents >>

Navigation:  Работа в режиме исполнения > Работа со средой исполнения >

Синхронизация времени узла

В MasterSCADA 4D можно реализовать синхронизацию узлов проекта по времени с использованием скрипта C# и ФБ SetDateAndTime.

Рассмотрим пример создания проекта, в котором будут реализованы: запрос времени по NTP c сервера времени и установка запрошенного времени в локальный узел.

Синхронизация узла с сервером времени

1. Создадим проект в среде разработки MasterSCADA 4D. В дерево системы добавим узел АРМ. Настройки узла оставим по умолчанию:

Synchron_uzla_time

2. Чтобы запросить время по протоколу NTP с сервера времени, нужно написать скрипт на языке C#. Для этого в проект добавим объект и программу C#:

Synchron_uzla_time_1

3. В программу добавим два параметра:

pRun - входной параметр типа Bool;

Параметр_1 - выходной параметр типа DT.

Synchron_uzla_time_2

4. В редакторе C# запишем следующий скрипт:

Скриншот скрипта

Текст скрипта

Synchron_uzla_time_3

public sealed class Program : ScriptBase

{

  public sealed class Program : ScriptBase

{

  public override void Execute()

{

  if (pRun) {

       Параметр_1 = GetNetworkTime();

   }

}

      public static DateTime GetNetworkTime()

       {

          //const string NtpServer = "pool.ntp.org";

          const string NtpServer = "ntp0.ntp-servers.net";

          /*

       https://www.ntp-servers.net/servers.html        

       Ярус    Адрес сервера     IPv6    Состояние    Нагрузка

       1    ntp0.ntp-servers.net    Есть    Работает    Средняя

       1    ntp1.ntp-servers.net    Нет     Работает    Высокая

       1    ntp2.ntp-servers.net    Есть    Работает    Высокая

       1    ntp3.ntp-servers.net    Есть    Работает    Средняя

       2    ntp4.ntp-servers.net    Есть    Работает    Низкая

       2    ntp5.ntp-servers.net    Нет     Работает    Низкая

       2    ntp6.ntp-servers.net    Есть    Работает    Низкая

       2    ntp7.ntp-servers.net    Нет     Работает    Низкая

            */

          const int DaysTo1900 = 1900 * 365 + 95; // 95 = offset for leap-years etc.

          const long TicksPerSecond = 10000000L;

          const long TicksPerDay = 24 * 60 * 60 * TicksPerSecond;

          const long TicksTo1900 = DaysTo1900 * TicksPerDay;

          var ntpData = new byte[48];

           ntpData[0] = 0x1B; // LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)

          var addresses = Dns.GetHostEntry(NtpServer).AddressList;

          var ipEndPoint = new IPEndPoint(addresses[0], 123);

          long pingDuration = Stopwatch.GetTimestamp(); // temp access (JIT-Compiler need some time at first call)

          using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))

           {

               socket.Connect(ipEndPoint);

               socket.ReceiveTimeout = 5000;

               socket.Send(ntpData);

               pingDuration = Stopwatch.GetTimestamp(); // after Send-Method to reduce WinSocket API-Call time

 

               socket.Receive(ntpData);

               pingDuration = Stopwatch.GetTimestamp() - pingDuration;

           }

          long pingTicks = pingDuration * TicksPerSecond / Stopwatch.Frequency;

          // optional: display response-time

          // Console.WriteLine("{0:N2} ms", new TimeSpan(pingTicks).TotalMilliseconds);

          long intPart = (long)ntpData[40] << 24 | (long)ntpData[41] << 16 | (long)ntpData[42] << 8 | ntpData[43];

          long fractPart = (long)ntpData[44] << 24 | (long)ntpData[45] << 16 | (long)ntpData[46] << 8 | ntpData[47];

          long netTicks = intPart * TicksPerSecond + (fractPart * TicksPerSecond >> 32);

          var networkDateTime = new DateTime(TicksTo1900 + netTicks + pingTicks / 2);

          return networkDateTime.ToLocalTime(); // without ToLocalTime() = faster

       }

}

}

Если параметр программы pRun будет равен TRUE, то Параметр_1 будет равен результату вызова метода GetNetworkTime(), т.е. времени сервера.

5. Добавим параметр ВремяСервера типа DT в дерево объектов и свяжем его с выходным параметром программы, перетащив параметр программы на параметр объекта:

Synchron_uzla_time_4

6. Чтобы в режиме исполнения была возможность синхронизировать время узла с временем сервера, добавим в объект программу FBD. В редактор из палитры элементов добавим ФБ SetDateAndTime:

Synchron_uzla_time_5

7. В программу FBD добавим 3 параметра:

Время сервера - входной параметр. Создадим его, перетащив одноименный параметр с дерева на клеммник входа;

Установить - входной параметр типа Bool;

ErrorCode - выходной параметр. Создадим его, перетащив одноименный выход ФБ на клеммник выхода.

Далее свяжем параметр Установить со входом ФБ Execute, а параметр Время сервера - со входом DataAndTime:

Synchron_uzla_time_6

8. Перейдем в режим исполнения проекта. По умолчанию Параметр_1 программы C# передает время: 0001-01-01-00:00, а параметр pRun равен False:

Synchron_uzla_time_7

При изменении значения параметра pRun на True, будет вызван метод программы GetNetworkTime() и время сервера передастся в ФБ SetDateAndTime, который будет устанавливать получаемые дату и время в системное время узла. Если изменить значение параметра программы FBD Установить, то изменение системного времени будет происходить по переднему фронту изменения значения данного входа.

Synchron_uzla_time_8

Смотрите также: