Example #1
0
        /// <summary>
        /// Отправляет NMS-сообщение <paramref name="query"/> и ожидает ответа.
        /// Асинхронная операция.
        /// </summary>
        /// <typeparam name="TMessage">Тип сообщения, потомок NmsMessage.</typeparam>
        /// <param name="query">Сообщение-запрос.</param>
        /// <param name="options">Параметры асинхронной операции.</param>
        /// <returns>
        ///  <see cref="Task{TResult}"/> асинхронная операция - ответное сообщение.
        /// </returns>
        /// <exception cref="AggregateException">Призошла ошибка в асинхронном коде. См. <see cref="Exception.InnerException"/></exception>
        /// <exception cref="TimeoutException">Ошибка по таймауту.</exception>
        /// <exception cref="TaskCanceledException">Операция прервана пользователем.</exception>
        /// <exception cref="NibusResponseException">Ошибка NiBUS.</exception>
        public async Task <TMessage> WaitForNmsResponseAsync <TMessage>(TMessage query, NibusOptions options = null)
            where TMessage : NmsMessage
        {
            //Contract.Requires(!IsDisposed);
            //Contract.Requires(
            //    query.Datagram.Destanation.Type == AddressType.Hardware
            //    || query.Datagram.Destanation.Type == AddressType.Net);

            options = GetDefaultOrClone(options);

            // Последнее сообщение в BroadcastBlock всегда остается! Незабываем его фильтровать.
            NmsMessage lastMessage;

            IncomingMessages.TryReceive(null, out lastMessage);

            var wob = new WriteOnceBlock <NmsMessage>(m => m);

            using (IncomingMessages.LinkTo(
                       wob,
                       m => !ReferenceEquals(lastMessage, m) && m.IsResponse && m.ServiceType == query.ServiceType &&
                       (query.Id == 0 || m.Id == query.Id) && (query.Datagram.Destanation == Address.Empty || m.Datagram.Source == query.Datagram.Destanation)))
            {
                for (var i = 0; i < options.Attempts; i++)
                {
                    await OutgoingMessages.SendAsync(query);

                    try
                    {
                        var response =
                            (TMessage)await wob.ReceiveAsync(options.Timeout, options.Token).ConfigureAwait(false);

                        if (response.ErrorCode != 0)
                        {
                            throw new NibusResponseException(response.ErrorCode);
                        }

                        return(response);
                    }
                    catch (TimeoutException)
                    {
                        Logger.Debug("Timeout {0}", i + 1);
                        if (i < options.Attempts - 1)
                        {
                            continue;
                        }
                        throw;
                    }
                }
            }

            // Эта точка недостижима при attempts > 0!
            throw new InvalidOperationException();
        }
Example #2
0
        private async Task <NmsRead> GetNmsReadResponseAsync(
            NmsMessage lastMessage, Address target, int id, NibusOptions options)
        {
            var wob = new WriteOnceBlock <NmsMessage>(m => m);

            using (IncomingMessages.LinkTo(
                       wob,
                       m => !ReferenceEquals(lastMessage, m) && m.IsResponse && m.ServiceType == NmsServiceType.Read &&
                       m.Id == id && (target == Address.Empty || m.Datagram.Source == target)))
            {
                var response = (NmsRead)await wob.ReceiveAsync(options.Timeout, options.Token).ConfigureAwait(false);

                if (response.ErrorCode != 0)
                {
                    throw new NibusResponseException(response.ErrorCode);
                }

                return(response);
            }
        }