/// <summary> /// /// </summary> public override void HandleOutcomingMessages() { DeviceContext device; String msg; DateTime time; Frame request; Transaction transaction; // 1. Проверяем статус устройства: // 1.1 Если устройство находится в состоянии Operational, ничего не делаем // 1.2 Если устройство находится в состоянии CommunicationError, ничего не делаем // 1.3 Если устройство находится в состоянии ConfigurationError, ничего не делаем // 1.4 Если устройства находится в состоянии Stopped, ничего не делаем // 1.5 Если устройство находится в состоянии Pre-operational, отправляем команду // перевода устройства в состояние Operational // 1.5.1 Проверяем // Сервис не работает if (_Status != Status.Running) { return; } // Получаем устройство _Context.Next(); device = _Context.CurrentDevice; // Проверяем статус if (device.Device.Status == DeviceStatus.Preoperational) { if (device.CurrentTransaction != null) { switch (device.CurrentTransaction.Status) { case TransactionStatus.Running: { // Запрос был уже отправлен. Проверяем таймаут time = device.CurrentTransaction.TimeOfStart; time = time.AddSeconds(device.Device.PollingInterval); if (time < DateTime.Now) { msg = String.Format("Service NMT: Timeout - устройство" + "не перешло в режим Operational за заданное время"); // Устройство не перешло из состояние Pre-Operational // за заданное время. Устанавливаем статус неудачной попытки device.CurrentTransaction.Abort(null, msg); } break; } case TransactionStatus.NotInitialized: case TransactionStatus.Completed: { // Устройство перешло в состояние Operational - транзакция выполнена // Однако, по какой-то причине устройство перешло в состояние Pre-Operational // Переводим устройство в состояние Operational request = new Frame(); request.Identifier = 0; request.FrameFormat = FrameFormat.StandardFrame; request.FrameType = FrameType.DATAFRAME; request.Data = new Byte[] { (Byte)StatusCode.Operational, // Поле комадны device.Device.NodeId // Поле Node ID }; transaction = new Transaction(); transaction.Start(TransactionType.BroadcastMode, request); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( transaction.Request.Value); } break; } case TransactionStatus.Aborted: { // Проверяем количество неудачных попыток и если оно // достигло предела не отсылаем устройству больше запросов if (device.ErrorCount < TotalAttempts) { // Повторяем запрос device.CurrentTransaction.Repeat(); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } break; } default: { msg = String.Format( "Network {0}: ServiceNmt - Обнаружен статус запроса {1} не поддерживаемый " + "в данной версии ПО", _NetworkController.Description, device.CurrentTransaction.Status); throw new Exception(msg); } } } else { // Отправляем команду для перевода устройства в состояние Operational request = new Frame(); request.Identifier = 0; request.FrameFormat = FrameFormat.StandardFrame; request.FrameType = FrameType.DATAFRAME; request.Data = new Byte[] { (Byte)StatusCode.Operational, // Поле комадны device.Device.NodeId // Поле Node ID }; device.CurrentTransaction = new Transaction(); device.CurrentTransaction.Start(TransactionType.UnicastMode, request); lock (_SyncRoot) { _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } } else { // Oбратная связь возникает через сервис NodeGuard, // который отслеживает состояние устройства. И только он может установить, что // устройство перешло режим Operational и устанавливает статус устройству. // По этому, проверяем состояние транзакции и если транзакция активна // и устройство изменило статус, то считаем что команда дошла до устройства // и завершаем транзакцию. if ((device.CurrentTransaction != null) && (device.CurrentTransaction.IsRunning)) { // Т.к сервис не получает ответа, останавливаем транзакцию // при помощи пустого фрайма (псевноответа) device.CurrentTransaction.Stop(new Frame()); } } }
/// <summary> /// Выполняет запрос к удалённому устройству /// (переберая устройства и объекты словаря) /// </summary> public override void HandleOutcomingMessages() { DeviceContext device; //ObjectInfo objInfo; // Сервис не работает if (_Status != Status.Running) { return; } if (_Context.Count == 0) { return; } // Устанавливаем следующее по списку устройство для обработки _Context.Next(); // Получаем устройство для обработки device = _Context.CurrentDevice; // Если устройство активно, выполняем запрос lock (_SyncRoot) { if ((device.Device.Status == DeviceStatus.Operational) || (device.Device.Status == DeviceStatus.Preoperational) || (device.Device.Status == DeviceStatus.Stopped)) { if (device.CurrentTransaction == null) { device.CurrentTransaction = new Transaction(); } // Проверяем, что последнй запрос (транзакция) к устройству выполнена // Если это так, начинаем новую, в противном случае ничего неделаем (ждём окончания транзакции) if (device.CurrentTransaction.IsRunning) { // Транзакция активна проверяем длительность транзакции if (device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval) <= DateTime.Now) { // Таймаут на запрос device.CurrentTransaction.Abort(null, "Request timeout"); // Пишем в лог... } return; } else { // Если запрос был успешным или неудачным, выжадаем требуемое время // для нового запроса if ((device.CurrentTransaction.Status == TransactionStatus.Aborted) || (device.CurrentTransaction.Status == TransactionStatus.Completed)) { if (device.CurrentTransaction.TimeOfStart.AddSeconds( device.Device.PollingInterval) > DateTime.Now) { return; } } if (device.CurrentTransaction.Status == TransactionStatus.Aborted) { if (device.ErrorCount < TotalAttempts) { // Повторяем запрос device.CurrentTransaction.Repeat(); // Отправляем сообщение к устройству _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); return; } else { device.CurrentTransaction = null; } } //Получаем следующий объект словаря для обработки device.Next(); if (!device.CurrentObject.SdoCanRead) { // Данный объект не обрабатывается сервисом SDO return; } Transaction trans = new Transaction(); Frame message = new Frame(); message.Identifier = System.Convert.ToUInt32(0x600 + device.Device.NodeId); message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.DATAFRAME; message.Data = new Byte[8]; message.Data[0] = 0x40; message.Data[1] = (byte)device.CurrentObject.Index; message.Data[2] = (byte)(device.CurrentObject.Index >> 8); device.CurrentTransaction = trans; trans.Start(TransactionType.UnicastMode, message); } // Отправляем сообщение к устройству _NetworkController.SendMessageToCanPort( device.CurrentTransaction.Request.Value); } } }
/// <summary> /// Конструктор для сериализации /// </summary> /// <param name="info"></param> /// <param name="context"></param> //public ServicePdoReceive(SerializationInfo info, StreamingContext context) // : base(info, context) //{ // _SynchronizationPeriod = info.GetInt32("Interval"); // _LastTimeSynchronisation = DateTime.Now; //} #endregion #region Methods /// <summary> /// /// </summary> public override void HandleOutcomingMessages() { //String msg; Frame message; if (Status != Status.Running) { return; } // 1. Один раз в период опроса (равен периoду) опрашиваем состояние устройства. // Получаем время последнего опроса устройства. Прибавляем к нему время прериода синхронизации времени // и сравниваем с текущим временем. Если полученное время меньше текущего, то выполняем синхронизацию. if (_LastTransaction != null) { TimeSpan interval = DateTime.Now - _LastTransaction.TimeOfEnd; if (interval.Seconds < Interval) { return; } } _LastTransaction = new Transaction(); // Формируем и записываем запрос в выходной буфер message = new Frame(); message.Identifier = 0x200; message.FrameFormat = FrameFormat.StandardFrame; message.FrameType = FrameType.DATAFRAME; message.Data = new Byte[4]; // Получаем текущее время в формате UNIX UInt32 unixTime = Unix.ToUnixTime(DateTime.Now); unchecked { message.Data[0] = (Byte)unixTime; // Младший байт message.Data[1] = (Byte)(unixTime >> 8); message.Data[2] = (Byte)(unixTime >> 16); message.Data[3] = (Byte)(unixTime >> 24); // Старший байт } _LastTransaction.Start(TransactionType.BroadcastMode, message); _NetworkController.SendMessageToCanPort(_LastTransaction.Request.Value); _LastTransaction.Stop(null); //Debug.WriteLine(String.Format("Время последней синхронизации времени: {0}", // now.ToString(new System.Globalization.CultureInfo("ru-Ru", false)))); }