public async Task RetriesOnOldTransactionUsingRetryCount()
        {
            // Arrange
            var request         = new ReadHoldingRegistersRequest(1, 1, 1);
            var oldResponse     = new ReadOnlySequence <byte>(new byte[] { 0, 1, 0, 0, 0, 5, 1, 3, 2, 0, 0 }.AsMemory());
            var newResponse     = new ReadOnlySequence <byte>(new byte[] { 0, 2, 0, 0, 0, 5, 1, 3, 2, 0, 0 }.AsMemory());
            var pipeAdapterMock = new Mock <IPipeResource>();

            pipeAdapterMock.Setup(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            pipeAdapterMock.SetupSequence(x => x.ReadAsync(It.IsAny <int>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(oldResponse)
            .ReturnsAsync(oldResponse)
            .ReturnsAsync(newResponse);
            var transactionIdProviderMock = new Mock <ITransactionIdProvider>();

            transactionIdProviderMock.Setup(x => x.NewId()).Returns(2);
            var target = new ModbusTcpTransport(pipeAdapterMock.Object, transactionIdProviderMock.Object, Mock.Of <ILogger <IModbusMaster> >())
            {
                Retries = 2
            };

            // Act
            var actual = await target.SendAsync <ReadHoldingRegistersResponse>(request);

            // Assert
            pipeAdapterMock.Verify(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>()), Times.Exactly(3));
            pipeAdapterMock.Verify(x => x.ReadAsync(It.IsAny <int>(), It.IsAny <CancellationToken>()), Times.Exactly(3));
        }
        public async Task ReadsPipeAgainIfNotEnoughtData()
        {
            // Arrange
            var request          = new ReadHoldingRegistersRequest(1, 1, 1);
            var response         = new byte[] { 0, 1, 0, 0, 0, 5, 1, 3, 2, 0, 0 };
            var responseSequence = new ReadOnlySequence <byte>(response.AsMemory());
            var pipeAdapterMock  = new Mock <IPipeResource>();

            pipeAdapterMock.Setup(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            pipeAdapterMock.Setup(x => x.ReadAsync(6, It.IsAny <CancellationToken>())).ReturnsAsync(responseSequence.Slice(0, 6));
            pipeAdapterMock.Setup(x => x.ReadAsync(11, It.IsAny <CancellationToken>())).ReturnsAsync(responseSequence);
            var transactionIdProviderMock = new Mock <ITransactionIdProvider>();

            transactionIdProviderMock.Setup(x => x.NewId()).Returns(1);

            var target = new ModbusTcpTransport(pipeAdapterMock.Object, transactionIdProviderMock.Object, Mock.Of <ILogger <IModbusMaster> >());

            // Act
            var actual = await target.SendAsync <ReadHoldingRegistersResponse>(request, It.IsAny <CancellationToken>());

            // Assert
            pipeAdapterMock.Verify(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>()), Times.Once());
            pipeAdapterMock.Verify(x => x.ReadAsync(6, It.IsAny <CancellationToken>()), Times.Once());
            pipeAdapterMock.Verify(x => x.ReadAsync(6, It.IsAny <CancellationToken>()), Times.Once());
            pipeAdapterMock.Verify(x => x.MarkExamined(responseSequence.Slice(0, 6)), Times.Once());
            pipeAdapterMock.Verify(x => x.MarkConsumed(responseSequence), Times.Once());
        }
        public async Task ThrowsOnOldTransactionIfDifferenceIsEqualToThreshold()
        {
            // Arrange
            var request         = new ReadHoldingRegistersRequest(1, 1, 1);
            var oldResponse     = new ReadOnlySequence <byte>(new byte[] { 0, 3, 0, 0, 0, 5, 1, 3, 2, 0, 0 }.AsMemory());
            var newResponse     = new ReadOnlySequence <byte>(new byte[] { 0, 5, 0, 0, 0, 5, 1, 3, 2, 0, 0 }.AsMemory());
            var pipeAdapterMock = new Mock <IPipeResource>();

            pipeAdapterMock.Setup(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            pipeAdapterMock.SetupSequence(x => x.ReadAsync(It.IsAny <int>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(oldResponse)
            .ReturnsAsync(newResponse);
            var transactionIdProviderMock = new Mock <ITransactionIdProvider>();

            transactionIdProviderMock.Setup(x => x.NewId()).Returns(2);
            var target = new ModbusTcpTransport(pipeAdapterMock.Object, transactionIdProviderMock.Object, Mock.Of <ILogger <IModbusMaster> >())
            {
                Retries = 0,
                RetryOnOldResponseThreshold = 2
            };

            // Act
            await Assert.ThrowsAsync <IOException>(() => target.SendAsync <ReadHoldingRegistersResponse>(request));

            // Assert
            pipeAdapterMock.Verify(x => x.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>()), Times.Once());
            pipeAdapterMock.Verify(x => x.ReadAsync(It.IsAny <int>(), It.IsAny <CancellationToken>()), Times.Once());
        }
        public void ModbusTransportThrowsOnInvalidWaitToRetryMilliseconds(int milliseconds)
        {
            // Arrange
            var transport = new ModbusTcpTransport(new Mock <IPipeResource>().Object, new Mock <ITransactionIdProvider>().Object, Mock.Of <ILogger <IModbusMaster> >());

            // Act/Assert
            Assert.Throws <ArgumentOutOfRangeException>(() => transport.WaitToRetryMilliseconds = milliseconds);
        }
Exemple #5
0
            internal void ReadFrameCompleted(IAsyncResult ar)
            {
                _log.DebugFormat("Read Frame completed {0} bytes", _stream.EndRead(ar));
                byte[] frame = CollectionUtility.Concat(_mbapHeader, _messageFrame);
                _log.InfoFormat("RX: {0}", StringUtility.Join(", ", frame));

                IModbusMessage request = ModbusMessageFactory.CreateModbusRequest(CollectionUtility.Slice(frame, 6, frame.Length - 6));

                request.TransactionID = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frame, 0));

                // TODO refactor
                ModbusTcpTransport transport = new ModbusTcpTransport();
                // perform action and build response
                IModbusMessage response = _slave.ApplyRequest(request);

                response.TransactionID = request.TransactionID;

                // write response
                byte[] responseFrame = transport.BuildMessageFrame(response);
                _log.InfoFormat("TX: {0}", StringUtility.Join(", ", responseFrame));
                _stream.BeginWrite(responseFrame, 0, responseFrame.Length, WriteCompleted, null);
            }
            internal void ReadFrameCompleted(IAsyncResult ar)
            {
                _log.DebugFormat("Read Frame completed {0} bytes", _stream.EndRead(ar));
                byte[] frame = CollectionUtility.Concat(_mbapHeader, _messageFrame);
                _log.InfoFormat("RX: {0}", StringUtility.Join(", ", frame));

                IModbusMessage request = ModbusMessageFactory.CreateModbusRequest(CollectionUtility.Slice(frame, 6, frame.Length - 6));
                request.TransactionID = (ushort) IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frame, 0));

                // TODO refactor
                ModbusTcpTransport transport = new ModbusTcpTransport();
                // perform action and build response
                IModbusMessage response = _slave.ApplyRequest(request);
                response.TransactionID = request.TransactionID;

                // write response
                byte[] responseFrame = transport.BuildMessageFrame(response);
                _log.InfoFormat("TX: {0}", StringUtility.Join(", ", responseFrame));
                _stream.BeginWrite(responseFrame, 0, responseFrame.Length, WriteCompleted, null);
            }