//[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="sender"></param> /// <param name="e"></param> private void EventHandler_TimerInterFrameDelay_Elapsed( object sender, ElapsedEventArgs e) { DataMessage message; ServiceErrorMessage errMessage; // Если сработал межкадровый таймер, значит сообщение полностью // принято. List<Byte> list = new List<byte>(); // Получаем массив байт принятого сообщения while(_serialPort.BytesToRead != 0) { list.Add((Byte)_serialPort.ReadByte()); } // Проверяем форат сообщения // Минимальная длина сообщения 1 байт: // [ADDR: 4 байта] + [CMD: 1 байт] + [DATA: 0 байт] + [CRC16: 2 байта] = 7 байт if (list.Count < 7) { //TODO: Ошибка. Создать служебное сообщение об ошибке errMessage = new ServiceErrorMessage { SpecificErrorCode = ErrorCode.IncorrectMessageLength, Description = "Неправильная длина сообщения", ExecutionTime = DateTime.Now }; _InputBuffer.Enqueue(errMessage); OnMessageReceived(); return; } // Проверяем CRC16 var array = new Byte[list.Count - 2]; list.CopyTo(0, array, 0, array.Length); if (!CRC16.CheckCRC16(list.ToArray())) { errMessage = new ServiceErrorMessage { SpecificErrorCode = ErrorCode.IncorrectCRC, Description = "Неправильная контрольная сумма", ExecutionTime = DateTime.Now }; _InputBuffer.Enqueue(errMessage); OnMessageReceived(); return; } // Получаем данные сообщения array = new Byte[list.Count - 7]; // 7 = 5 [adr:4 cmd: 1] + 2 [crc16: 2] list.CopyTo(5, array, 0, array.Length); // Получаем адрес устройства UInt32 adr = 0; //adr |= ((UInt32)list[3] << 24); //adr |= ((UInt32)list[2] << 16); //adr |= ((UInt32)list[1] << 8); //adr |= list[0]; var arrayAdr = new Byte[4]; list.CopyTo(0, arrayAdr, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(arrayAdr); adr = BitConverter.ToUInt32(arrayAdr, 0); message = new DataMessage(array) { MessageType = MessageType.IncomingMessage, Address = adr, CmdCode = list[4], ExecutionTime = DateTime.Now }; // Формируем сообщение и сохраняем его в буфер _InputBuffer.Enqueue(message); OnMessageReceived(); }
/// <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(); } } }
/// <summary> /// Обработчик приёма сообщения из сети /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected override void EventHandler_Connection_MessageReceived( object sender, EventArgs e) { IDataLinkPort port = (IDataLinkPort)sender; var messages = new List<MessageBase>(); // Читаем входящие сообщения из входного буфера порта while(port.MessagesToRead > 0) { var msg = port.Read(); messages.Add((MessageBase)msg); } // Обрабатываем сервисные сообщения var serviceErrorMessages = messages .Where(y => y.MessageType == MessageType.ServiceErrorMessage) .Select(z => (ServiceErrorMessage)z); foreach (var msg in serviceErrorMessages) { //запись в лог ошибок Logger.Error(String.Format("Controller Id={0} | Ошибка Code={1} | Description={2}", _Id, msg.Code, msg.Description)); //TODO: Сделать обработчик ошибок, если потребуется //switch (msg.SpecificErrorCode) //{ // case ErrorCode. //} } // TODO: сделать сервистные сообщения, если понадобятся //var serviceInfoMessages = messages // .Where(y => y.MessageType == MessageType.ServiceInfoMessage) // .Select(z => (....)); var dataMessages = messages .Where(y => y.MessageType == MessageType.IncomingMessage) .Select(z => (DataMessage)z).ToArray(); if (dataMessages.Length > 1) { throw new Exception( "Сетевой контроллер принял одновременно более одного сообщения из сети"); } if ((_currentNetworkRequest == null) || (_currentNetworkRequest.Status != NetworkRequestStatus.Running)) { throw new Exception("Принято сообщение в отсутствии запроса"); } // Обрабатывает сообщение _CurrentIncomingMessage = dataMessages[0]; _autoResetEventRequest.Set(); }
public void TestReadGroupAddressSuccess() { // Arrange int amount = 1; 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.GetType()).Returns(typeof(IncotexNetworkController)); comPort.Setup(p => p.IsOpen).Returns(true); comPort.Setup(p => p.MessagesToRead) .Returns(() => amount) .Callback(() => amount--); 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; controller.Start(); //controller.Stop(); var device = new Mercury203() { Address = 1, }; controller.Devices.Add(device); // Act var result = device.ReadGroupAddress(); //controller.Write(trans); do { // Ждём выполения комманды } while (!result.IsCompleted); // Assert Assert.AreEqual(TransactionStatus.Completed, result.Stack[result.Stack.Length - 1].Status, "Success"); }
//[ExpectedException(typeof(InvalidOperationException), "")] public void TestReadGroupAddressByControllerIsStopped() { // 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; controller.Stop(); // Контроллер остановлен var device = new Mercury203() { Address = 1, }; controller.Devices.Add(device); Type type = null; // Act try { var result = device.ReadGroupAddress(); } catch (Exception ex) { type = ex.GetType(); } // Assert Assert.AreEqual(typeof(InvalidOperationException), type); // Assert //while(true) //{ // Ждём должно быть исключение //} }
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> /// Установка тарифа (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; }
/// <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; }