/// <summary> /// Записывает запрос в выходной буфер /// </summary> /// <param name="request">Сетевой запрос</param> /// <param name="isExternalCall">Признак внешнего вызова</param> internal void Enqueue(NetworkRequest request, bool isExternalCall) { if (isExternalCall) { _OutputBufferExternalCalls.Enqueue(request); } else { _OutputBufferInternalCalls.Enqueue(request); } }
//[ExpectedException(typeof(InvalidOperationException), "")] public void TestWriteByWrongReqeustType() { // Arrange var msg = new DataMessage(new byte[] { 0, 0, 0, 2 }) { Address = 1, CmdCode = 0x20, MessageType = MessageType.IncomingMessage }; Mock<IDataLinkPort> comPort = new Mock<IDataLinkPort>(); comPort.Setup(p => p.IsOpen).Returns(true); comPort.Setup(p => p.MessagesToRead).Returns(0); comPort.Setup(p => p.Write(It.IsAny<IMessage>())) .Raises(m => m.MessageReceived += null, new EventArgs()); comPort.Setup(p => p.Read()).Returns(msg); var controller = new IncotexNetworkController(); controller.Connection = comPort.Object; var device = new Mercury203(); controller.Devices.Add(device); controller.Start(); var request = new DataMessage() { Address = 0x1, CmdCode = Convert.ToByte(Mercury203CmdCode.ReadGroupAddress) }; var wrongTrans = new Transaction(null, TransactionType.Undefined, request) { Sender = device }; // Ошибка !!! var networkRequest = new NetworkRequest(wrongTrans); // Act try { controller.Write(networkRequest); while (networkRequest.Status != NetworkRequestStatus.Failed) { // Ждём, должно быть исключение } } catch (Exception ex) { // Assert Assert.AreEqual(typeof(InvalidOperationException), ex.GetType()); } }
/// <summary> /// Выполняет сетевую транзакцию /// </summary> /// <param name="networkRequest"></param> public void ExecuteTransaction(NetworkRequest networkRequest) { if ((CurrentNetworkRequest != null) && (CurrentNetworkRequest.Status == NetworkRequestStatus.Running)) { throw new InvalidOperationException( "Попытка выполнить транзакцию во время действия другой"); } if ((networkRequest.CurrentTransaction.TransactionType != TransactionType.BroadcastMode) && (networkRequest.CurrentTransaction.TransactionType != TransactionType.UnicastMode)) { networkRequest.CurrentTransaction.Start(); networkRequest.CurrentTransaction.Abort(new TransactionError { ErrorCode = TransactionErrorCodes.TransactionTypeIsWrong, Description = "Попытка запустить сетевую транзакцию с недопустимым типом" }); throw new InvalidOperationException( String.Format("Попытка запустить сетевую транзакцию с недопустимым типом: {0}", networkRequest.CurrentTransaction.TransactionType)); } // Устанавливаем транзакцию в качестве текущей _currentNetworkRequest = networkRequest; var result = _currentNetworkRequest.AsyncRequestResult; // Если запрос адресованный, то ждём ответа // Если запрос широковещательный выдерживаем установленную паузу switch (_currentNetworkRequest.CurrentTransaction.TransactionType) { case TransactionType.UnicastMode: { var disconnected = false; for (int i = 0; i < TotalAttempts; i++) { // Отправляем запрос к удалённому устройтву _currentNetworkRequest.CurrentTransaction.Start(); _Connection.Write(_currentNetworkRequest.CurrentTransaction.Request); // Ждём ответа от удалённого устройтва или тайм аут if (!_autoResetEventRequest.WaitOne(_requestTimeout)) { // TimeOut!!! Прекращает текущую транзакцию _currentNetworkRequest.CurrentTransaction.Abort(new TransactionError { ErrorCode = TransactionErrorCodes.RequestTimeout, Description = "Request timeout" }); Transaction trn; // Повторяем запрос _currentNetworkRequest.NextAttempt(out trn); disconnected = true; continue; } else { // Ответ получен _currentNetworkRequest.CurrentTransaction.Stop(_CurrentIncomingMessage); _CurrentIncomingMessage = null; disconnected = false; break; } } // Кол-во попыток доступа к устройтсву исчерпано if (disconnected) { //var errors = ((DeviceBase)_CurrentNetworkRequest.CurrentTransaction.Sender).Errors; //errors.CommunicationError = true; //((DeviceBase)_CurrentNetworkRequest.CurrentTransaction.Sender).SetError(errors); } else { // Если ранее была установлена ошибка связи, то сбрасываем её //var errors = ((DeviceBase)_CurrentNetworkRequest.CurrentTransaction.Sender).Errors; //if (errors.CommunicationError == true) //{ // errors.CommunicationError = false; // ((DeviceBase)_CurrentNetworkRequest.CurrentTransaction.Sender).SetError(errors); //} } result.SetCompleted(); OnNetwrokRequestCompleted( new NetworkRequestCompletedArgs { NetworkRequest = _currentNetworkRequest }); break; } case TransactionType.BroadcastMode: { // Отправляем запрос к удалённому устройтву _currentNetworkRequest.CurrentTransaction.Start(); _Connection.Write(_currentNetworkRequest.CurrentTransaction.Request); if (!_autoResetEventRequest.WaitOne(_broadcastRequestDelay)) { _currentNetworkRequest.CurrentTransaction.Stop(null); } else { _CurrentIncomingMessage = null; throw new Exception( "Принят ответ от удалённого устройтства во время широковещательного запроса"); } result.SetCompleted(); OnNetwrokRequestCompleted( new NetworkRequestCompletedArgs { NetworkRequest = _currentNetworkRequest }); break; } default: { result.SetCompleted(); throw new NotSupportedException(); } } }
public override IAsyncRequestResult Write( NetworkRequest networkRequest, bool isExternalCall = true) { lock (_syncRoot) { if (Status == Status.Running) { networkRequest.TotalAttempts = TotalAttempts; _outputBuffer.Enqueue(networkRequest, isExternalCall); _autoResetEventWorker.Set(); return (IAsyncRequestResult)networkRequest.AsyncRequestResult; } else { throw new InvalidOperationException( "Невозможно выполнить операцию. Контроллер остановлен"); } } }
/// <summary> /// Записывает транзакцию в буфер исходящих сообщений /// </summary> /// <param name="request"></param> /// <param name="isExternalCall"></param> public abstract IAsyncRequestResult Write(NetworkRequest request, bool isExternalCall);
/// <summary> /// Разбирает ответ по запросу ReadGroupAddress (CMD=20h) /// </summary> /// <param name="transaction"></param> private void GetAnswerReadGroupAddress(NetworkRequest networkRequest) { // Разбираем ответ if (networkRequest.Status == NetworkRequestStatus.Completed) { var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); if (command == null) { throw new Exception("Не найдена команда с указанной транзакцией"); } if (networkRequest.CurrentTransaction.Answer.ToArray().Length != 11) { //command.Status = Result.Error; //command.ErrorDescription = "Неверная длина ответного сообщения"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } var request = (DataMessage)networkRequest.Request.Request; var answer = (DataMessage)networkRequest.CurrentTransaction.Answer; // Проверяем новый адрес в запросе и в ответе if (request.Address != answer.Address) { //command.Status = Result.Error; //command.ErrorDescription = "Адрес команды в ответе не соответствует адресу в запросе"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } if (answer.CmdCode != request.CmdCode) { //command.Status = Result.Error; //command.ErrorDescription = "Код команды в ответе не соответствует коду в запросе"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } // Получаем параметр // Присваиваем новое значение параметру var parameter = _parameters[ParameterNamesMercury203.GADDR]; parameter.Value = parameter.ValueConverter.FromArray( new byte[] { answer.Data[0], answer.Data[1], answer.Data[2], answer.Data[3] }); //command.Status = Result.OK; _activeRequests.Remove(command); } else { // Транзакция выполнена с ошибкам var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); //command.Status = Result.Error; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } }
public AsyncRequestResult(NetworkRequest networkCommand) { if (networkCommand == null) { throw new ArgumentNullException("networkCommand", String.Empty); } _NetworkRequest = networkCommand; }
/// <summary> /// Установка тарифа (CMD=0Bh) /// </summary> /// <param name="value"></param> /// <param name="isExternalCall"></param> /// <returns></returns> public IAsyncRequestResult WriteActiveTariff(byte value, bool isExternalCall = true) { if ((value < 1) || (value > 4)) { throw new ArgumentOutOfRangeException("Amount", "Действующий тарифов должн быть от 1 до 4"); } var request = new DataMessage( Mpower.GetValueConveter().ToArray(value)) { Address = Address, CmdCode = Convert.ToByte(Mercury203CmdCode.WriteActiveTariff) }; var transaction = new Transaction(this, TransactionType.UnicastMode, request) { Sender = this }; var networkRequest = new NetworkRequest(transaction); if (_NetworkController == null) { transaction.Start(); transaction.Abort(new TransactionError { ErrorCode = TransactionErrorCodes.DataLinkPortNotInstalled, Description = "Невозможно выполенить запрос. Не установлен контроллер сети" }); networkRequest.AsyncRequestResult.SetCompleted(); } else { _activeRequests.Add(networkRequest); _NetworkController.Write(networkRequest, isExternalCall); } return (IAsyncRequestResult)networkRequest.AsyncRequestResult; }
public IAsyncRequestResult ReadGroupAddress(bool isExternalCall = true) { var request = new DataMessage() { Address = Address, CmdCode = Convert.ToByte(Mercury203CmdCode.ReadGroupAddress) }; var transaction = new Transaction(this, TransactionType.UnicastMode, request) { Sender = this }; var networkRequest = new NetworkRequest(transaction); if (_NetworkController == null) { transaction.Start(); transaction.Abort(new TransactionError { ErrorCode = TransactionErrorCodes.DataLinkPortNotInstalled, Description = "Невозможно выполенить запрос. Не установлен контроллер сети" }); networkRequest.AsyncRequestResult.SetCompleted(); } else { _activeRequests.Add(networkRequest); _NetworkController.Write(networkRequest, isExternalCall); } return (IAsyncRequestResult)networkRequest.AsyncRequestResult; }
/// <summary> /// Широковешательная команда записи времени и даты во все устройтсва /// сети с указанным групповым адресом /// </summary> /// <param name="dateTime"></param> /// <param name="groupAddress">Групповой адрес устройтсв</param> /// <param name="networkController"></param> /// <param name="isExternalCall"></param> /// <returns></returns> /// <remarks>Ответ на данный тип запросов не приходит, /// только создаётся временная выдержка</remarks> public static IAsyncRequestResult WriteDateTimeInGroupDevices( DateTime dateTime, UInt32 groupAddress, INetwrokController networkController, bool isExternalCall = true) { var request = new DataMessage( new IncotexDataTimeTypeConverter().ToArray(IncotexDateTime.FromDateTime(dateTime))) { Address = groupAddress, CmdCode = Convert.ToByte(Mercury203CmdCode.WriteDateTime) }; var transaction = new Transaction(null, TransactionType.BroadcastMode, request) { Sender = null }; var networkRequest = new NetworkRequest(transaction); if (networkController == null) { transaction.Start(); transaction.Abort(new TransactionError { ErrorCode = TransactionErrorCodes.DataLinkPortNotInstalled, Description = "Невозможно выполенить запрос. Не установлен контроллер сети" }); networkRequest.AsyncRequestResult.SetCompleted(); } else { networkController.Write(networkRequest, isExternalCall); } return (IAsyncRequestResult)networkRequest.AsyncRequestResult; }
/// <summary> /// Разбирает ответ на запрос записи параметра, общий для команд /// записи имеющий структуру ADDR-CMD-CRC /// </summary> /// <param name="networkRequest"></param> private void GetAnswerGeneralWriteRequest(NetworkRequest networkRequest) { // Разбираем ответ if (networkRequest.Status == NetworkRequestStatus.Completed) { var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); if (command == null) { throw new Exception("Не найдена команда с указанной транзакцией"); } if (networkRequest.CurrentTransaction.Answer.ToArray().Length != 7) { //command.Status = Result.Error; //command.ErrorDescription = "Неверная длина ответного сообщения"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } var request = (DataMessage)networkRequest.Request.Request; var answer = (DataMessage)networkRequest.CurrentTransaction.Answer; // Проверяем новый адрес в запросе и в ответе if (request.Address != answer.Address) { //command.Status = Result.Error; //command.ErrorDescription = "Адрес команды в ответе не соответствует адресу в запросе"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } if (answer.CmdCode != request.CmdCode) { //command.Status = Result.Error; //command.ErrorDescription = "Код команды в ответе не соответствует коду в запросе"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } //command.Status = Result.OK; _activeRequests.Remove(command); } else { // Транзакция выполнена с ошибкам var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); //command.Status = Result.Error; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: _activeRequests.Remove(command); } }
/// <summary> /// Разбирает ответ от удалённого устройтва по запросу SetNewAddress (CMD=00h) /// </summary> /// <param name="networkRequest"></param> private void GetAnswerWriteAdderss(NetworkRequest networkRequest) { var request = (DataMessage)networkRequest.Request.Request; // Разбираем ответ if (networkRequest.Status == NetworkRequestStatus.Completed) { var requestArray = networkRequest.Request.Request.ToArray(); var answerArray = networkRequest.CurrentTransaction.Answer.ToArray(); var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); if (command == null) { throw new Exception("Не найдена команда с указанной транзакцией"); } if (answerArray.Length != 7) { //command.Status = Result.Error; //command.ErrorDescription = "Неверная длина ответного сообщения"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: Пишем в лог _activeRequests.Remove(command); } if (answerArray[4] != request.CmdCode) { //command.Status = Result.Error; //command.ErrorDescription = "Код команды в ответе не соответствует коду в запросе"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: Пишем в лог _activeRequests.Remove(command); } // Проверяем новый адрес в запросе и в ответе if ((requestArray[6] != answerArray[0]) || (requestArray[7] != answerArray[1]) || (requestArray[8] != answerArray[2]) || (requestArray[9] != answerArray[3])) { //command.Status = Result.Error; //command.ErrorDescription = // "Новый адрес счётчика в ответе не соответствует устанавливаемому"; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: Пишем в лог _activeRequests.Remove(command); } //Всё в порядке выполняем изменение сетевого адреса var converter = new BigEndianUInt32ValueConverter(); var adr = (UInt32)converter.FromArray( new Byte[] { answerArray[0], answerArray[1], answerArray[2], answerArray[3] }); Address = adr; //command.Status = Result.OK; _activeRequests.Remove(command); } else { // Транзакция выполнена с ошибкам var command = _activeRequests.FirstOrDefault( p => p.Id == networkRequest.Id); //command.Status = Result.Error; //OnErrorOccurred(new ErrorOccuredEventArgs() { DescriptionError = command.ToString() }); //TODO: Пишем в лог _activeRequests.Remove(command); } }
private void GetAnswer(NetworkRequest networkRequest) { var request = (DataMessage)networkRequest.Request.Request; //ищем устройтво var device = (Mercury203)_NetworkController.Devices[request.Address]; switch ((Mercury203CmdCode)request.CmdCode) { case Mercury203CmdCode.WriteAddress: { GetAnswerWriteAdderss(networkRequest); break; } case Mercury203CmdCode.WriteGroupAddress: { GetAnswerGeneralWriteRequest(networkRequest); break; } case Mercury203CmdCode.WriteDateTime: { GetAnswerGeneralWriteRequest(networkRequest); break; } case Mercury203CmdCode.WriteLimitPower: { GetAnswerGeneralWriteRequest(networkRequest); break; } case Mercury203CmdCode.WriteAmountOfActiveTariffs: { GetAnswerGeneralWriteRequest(networkRequest); break; } case Mercury203CmdCode.ReadGroupAddress: { GetAnswerReadGroupAddress(networkRequest); break; } case Mercury203CmdCode.ReadDateTime: { GetAnswerReadDateTime(networkRequest); break; } case Mercury203CmdCode.ReadTariffAccumulators: { GetAnswerReadTariffAccumulators(networkRequest); break; } case Mercury203CmdCode.ReadPowerLimit: { GetAnswerPowerLimit(networkRequest); break; } default: { throw new NotImplementedException( String.Format("Устройтво Mercury 203 не поддерживает команду с кодом {0}", request.CmdCode)); } } }
public IAsyncRequestResult Write( NetworkRequest request, bool isExternalCall) { throw new NotImplementedException(); }