示例#1
0
        public async Task RetriesOnSlaveExceptionCodeSlaveDeviceBusyIgnoringRetryCount()
        {
            // Arrange
            var target = new Mock <ModbusTransport>(new Mock <IPipeResource>().Object, Mock.Of <ITransactionIdProvider>(), Mock.Of <ILogger <IModbusMaster> >())
            {
                CallBase = true
            };

            target.Object.Retries = 3;
            target.Object.SlaveBusyUsesRetryCount = false;
            var request  = new ReadHoldingRegistersRequest(1, 1, 1);
            var response = ModbusResponseFactory.CreateResponse <ReadHoldingRegistersResponse>(
                new byte[] { 1, 3, 2, 0, 1 });
            var busyResponse = ModbusResponseFactory.CreateResponse <SlaveExceptionResponse>(
                new byte[] { 1, 129, (byte)SlaveExceptionCode.SlaveDeviceBusy });

            target.SetupWriteRequestAsync(request);
            target.SetupReadResponseAsync <ReadHoldingRegistersResponse>(busyResponse, busyResponse, busyResponse, busyResponse, response);

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

            // Assert
            Assert.Equal(response, actual);

            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.WriteRequestAsync(request, It.IsAny <CancellationToken>()), Times.Exactly(5));
            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.ReadResponseAsync <ReadHoldingRegistersResponse>(It.IsAny <CancellationToken>()), Times.Exactly(5));
            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.RetryReadResponse(request, response), Times.Once());
            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.Validate(request, response), Times.Once());
        }
        protected override async Task <IModbusResponse> ReadResponseAsync <TResponse>(CancellationToken token = default)
        {
            var buffer = await PipeResource.ReadAsync(MbapHeaderSizeOnResponse, token).ConfigureAwait(false);

            var frameDataLength = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt16(buffer.Slice(4, 2).ToSpan()));
            var totalLength     = MbapHeaderSizeOnResponse + frameDataLength;

            if (buffer.Length < totalLength)
            {
                PipeResource.MarkExamined(buffer);
                buffer = await PipeResource.ReadAsync(totalLength, token).ConfigureAwait(false);
            }

            var processedSequence = buffer.Slice(0, MbapHeaderSizeOnResponse + frameDataLength);

            var response = ModbusResponseFactory.CreateResponse <TResponse>(
                processedSequence
                .Slice(MbapHeaderSizeOnResponse, processedSequence.Length - MbapHeaderSizeOnResponse)
                .ToSpan());

            response.TransactionId = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(processedSequence.Slice(0, 2).ToSpan()));
            PipeResource.MarkConsumed(processedSequence);

            return(response);
        }
示例#3
0
        public async Task ThrowsOnSlaveExceptionResponse(SlaveExceptionCode exceptionCode)
        {
            // Arrange
            var target = new Mock <ModbusTransport>(new Mock <IPipeResource>().Object, Mock.Of <ITransactionIdProvider>(), Mock.Of <ILogger <IModbusMaster> >())
            {
                CallBase = true
            };
            var request  = new ReadHoldingRegistersRequest(1, 1, 1);
            var response = ModbusResponseFactory.CreateResponse <SlaveExceptionResponse>(
                new byte[] { 1, 129, (byte)exceptionCode });

            target.SetupWriteRequestAsync(request);
            target.SetupReadResponseAsync <ReadHoldingRegistersResponse>(response);

            // Act
            var ex = await Assert.ThrowsAsync <SlaveException>(() => target.Object.SendAsync <ReadHoldingRegistersResponse>(request));

            // Assert
            Assert.Equal(1, ex.SlaveAddress);
            Assert.Equal(129, ex.FunctionCode);
            Assert.Equal(exceptionCode, ex.SlaveExceptionCode);

            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.WriteRequestAsync(request, It.IsAny <CancellationToken>()), Times.Once());
            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.ReadResponseAsync <ReadHoldingRegistersResponse>(It.IsAny <CancellationToken>()), Times.Once());
        }
示例#4
0
        protected override async Task <IModbusResponse> ReadResponseAsync <TResponse>(CancellationToken token = default)
        {
            var buffer = await PipeResource.ReadAsync(token).ConfigureAwait(false);

            while (buffer.Length < MbapHeaderSizeOnResponse)
            {
                PipeResource.AdvanceTo(buffer.Start);
                buffer = await PipeResource.ReadAsync(token).ConfigureAwait(false);
            }

            var frameLength = (ushort)IPAddress.HostToNetworkOrder(NetCoreBitConverter.ToInt16(buffer.Slice(4, 2).ToSpan()));

            while (buffer.Length < MbapHeaderSizeOnResponse + frameLength)
            {
                PipeResource.AdvanceTo(buffer.Start);
                buffer = await PipeResource.ReadAsync(token).ConfigureAwait(false);
            }

            var processedSequence = buffer.Slice(0, MbapHeaderSizeOnResponse + frameLength);

            var response = ModbusResponseFactory.CreateResponse <TResponse>(
                processedSequence.Slice(MbapHeaderSizeOnResponse, processedSequence.Length - MbapHeaderSizeOnResponse).ToSpan());

            response.TransactionId = (ushort)IPAddress.NetworkToHostOrder(NetCoreBitConverter.ToInt16(buffer.Slice(0, 2).ToSpan()));

            PipeResource.AdvanceTo(processedSequence.End);

            return(response);
        }
示例#5
0
        protected override async Task <IModbusResponse> ReadResponseAsync <TResponse>(CancellationToken token = default)
        {
            var buffer = await PipeResource.ReadAsync(ResponseFrameStartSize, token).ConfigureAwait(false);

            var lengthSequence = buffer.Slice(0, ResponseFrameStartSize);

            var frameDataLength = GetResponseDataSize(lengthSequence.ToSpan());
            var totalLength     = ResponseFrameStartSize + frameDataLength + CrcSize;

            if (buffer.Length < totalLength)
            {
                PipeResource.MarkExamined(lengthSequence);
                buffer = await PipeResource.ReadAsync(totalLength, token).ConfigureAwait(false);
            }

            var processedSequence = buffer.Slice(0, totalLength);

            var expectedCrc = crcCalculator.Calculate(processedSequence.Slice(0, totalLength - CrcSize).ToMemory());
            var actualCrc   = BitConverter.ToUInt16(processedSequence.Slice(totalLength - CrcSize, CrcSize).ToSpan());

            if (actualCrc != expectedCrc)
            {
                PipeResource.MarkConsumed(processedSequence);
                throw new IOException($"Received unexpected CRC. Expected: {expectedCrc}. Received: {actualCrc}.");
            }

            var response = ModbusResponseFactory.CreateResponse <TResponse>(processedSequence.ToSpan());

            PipeResource.MarkConsumed(processedSequence);

            return(response);
        }
        public async Task ThrowsOnSlaveExceptionCodeSlaveDeviceBusyWhenExceedesRetryCount()
        {
            // Arrange
            var target = new Mock <ModbusTransport>(new Mock <IPipeResource>().Object, Mock.Of <IModbusLogger>(), Mock.Of <ITransactionIdProvider>())
            {
                CallBase = true
            };

            target.Object.Retries = 2;
            target.Object.SlaveBusyUsesRetryCount = true;
            var request      = new ReadHoldingRegistersRequest(1, 1, 1);
            var busyResponse = ModbusResponseFactory.CreateResponse <SlaveExceptionResponse>(
                new byte[] { 1, 129, (byte)SlaveExceptionCode.SlaveDeviceBusy });

            target.SetupWriteRequestAsync(request);
            target.SetupReadResponseAsync <ReadHoldingRegistersResponse>(busyResponse);

            // Act
            var ex = await Assert.ThrowsAsync <SlaveException>(() => target.Object.SendAsync <ReadHoldingRegistersResponse>(request));

            // Assert
            Assert.Equal(1, ex.SlaveAddress);
            Assert.Equal(129, ex.FunctionCode);
            Assert.Equal(SlaveExceptionCode.SlaveDeviceBusy, ex.SlaveExceptionCode);

            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.WriteRequestAsync(request, It.IsAny <CancellationToken>()), Times.Exactly(3));
            target.Protected().As <IModbusTransportMock>()
            .Verify(x => x.ReadResponseAsync <ReadHoldingRegistersResponse>(It.IsAny <CancellationToken>()), Times.Exactly(3));
        }
        public void CreatesReadInputsResponse()
        {
            // Arrange/Act
            ReadInputsResponse response = (ReadInputsResponse)ModbusResponseFactory.CreateResponse <ReadInputsResponse>(
                new byte[] { 11, ModbusFunctionCodes.ReadInputs, 1, 1 });

            // Assert
            Assert.Equal(ModbusFunctionCodes.ReadInputs, response.FunctionCode);
            Assert.Equal(11, response.SlaveAddress);
            Assert.Equal(new bool[] { true, false, false, false }, response.Data.Slice(0, 4).ToArray());
        }
        public void CreatesResponseSlaveExceptionResponse()
        {
            // Arrange/Act
            SlaveExceptionResponse response = (SlaveExceptionResponse)ModbusResponseFactory
                                              .CreateResponse <SlaveExceptionResponse>(new byte[] { 11, 129, 2 });

            // Assert
            Assert.Equal(129, response.FunctionCode);
            Assert.Equal(11, response.SlaveAddress);
            Assert.Equal(SlaveExceptionCode.IllegalDataAddress, response.SlaveExceptionCode);
        }
        public void CreatesResponseReadInputRegistersResponse()
        {
            // Arrange/Act
            ReadInputRegistersResponse response = (ReadInputRegistersResponse)ModbusResponseFactory
                                                  .CreateResponse <ReadInputRegistersResponse>(
                new byte[] { 11, ModbusFunctionCodes.ReadInputRegisters, 4, 0, 3, 0, 4 });

            // Assert
            Assert.Equal(ModbusFunctionCodes.ReadInputRegisters, response.FunctionCode);
            Assert.Equal(11, response.SlaveAddress);
            Assert.Equal(new ushort[] { 3, 4 }, response.Data);
        }
        public void CreatesWriteSingleRegisterResponse()
        {
            // Arrange/Act
            WriteSingleRegisterResponse response = (WriteSingleRegisterResponse)ModbusResponseFactory
                                                   .CreateResponse <WriteSingleRegisterResponse>(
                new byte[] { 17, ModbusFunctionCodes.WriteSingleRegister, 0, 1, 0, 3 });

            // Assert
            Assert.Equal(ModbusFunctionCodes.WriteSingleRegister, response.FunctionCode);
            Assert.Equal(17, response.SlaveAddress);
            Assert.Equal(1, response.StartAddress);
            Assert.Equal(3, response.Value);
        }
        public void CreatesWriteSingleCoilResponse()
        {
            // Arrange/Act
            WriteSingleCoilResponse response = (WriteSingleCoilResponse)ModbusResponseFactory
                                               .CreateResponse <WriteSingleCoilResponse>(
                new byte[] { 17, ModbusFunctionCodes.WriteSingleCoil, 0, 172, byte.MaxValue, 0 });

            // Assert
            Assert.Equal(ModbusFunctionCodes.WriteSingleCoil, response.FunctionCode);
            Assert.Equal(17, response.SlaveAddress);
            Assert.Equal(172, response.StartAddress);
            Assert.Equal(Constants.CoilOn, response.Value);
        }
        public void CreatesWriteMultipleCoilsResponse()
        {
            // Arrange/Act
            WriteMultipleCoilsResponse response = (WriteMultipleCoilsResponse)ModbusResponseFactory
                                                  .CreateResponse <WriteMultipleCoilsResponse>(
                new byte[] { 17, ModbusFunctionCodes.WriteMultipleCoils, 0, 19, 0, 10 });

            // Assert
            Assert.Equal(ModbusFunctionCodes.WriteMultipleCoils, response.FunctionCode);
            Assert.Equal(17, response.SlaveAddress);
            Assert.Equal(19, response.StartAddress);
            Assert.Equal(10, response.NumberOfPoints);
        }
示例#13
0
        public static TheoryData <IModbusRequest, IModbusResponse> GetTestValidationData()
        {
            var theoryData = new TheoryData <IModbusRequest, IModbusResponse>
            {
                {
                    new ReadCoilsRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 1, 1 }))
                },
                {
                    new ReadCoilsRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 2, 1, 1 }))
                },
                {
                    new ReadCoilsRequest(1, 1, 9),
                    ModbusResponseFactory.CreateResponse <ReadCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 1, 1 }))
                },
                {
                    new ReadInputsRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadInputsResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 1, 1 }))
                },
                {
                    new ReadInputsRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadInputsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 1, 1 }))
                },
                {
                    new ReadInputsRequest(1, 1, 9),
                    ModbusResponseFactory.CreateResponse <ReadInputsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 1, 1 }))
                },
                {
                    new ReadHoldingRegistersRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadHoldingRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 1, 1 }))
                },
                {
                    new ReadHoldingRegistersRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadHoldingRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 1, 1 }))
                },
                {
                    new ReadHoldingRegistersRequest(1, 1, 2),
                    ModbusResponseFactory.CreateResponse <ReadHoldingRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 3, 2, 1, 1 }))
                },
                {
                    new ReadInputRegistersRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadInputRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 1, 1 }))
                },
                {
                    new ReadInputRegistersRequest(1, 1, 1),
                    ModbusResponseFactory.CreateResponse <ReadInputRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 1, 1 }))
                },
                {
                    new ReadInputRegistersRequest(1, 1, 2),
                    ModbusResponseFactory.CreateResponse <ReadInputRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 4, 2, 1, 1 }))
                },
                {
                    new WriteSingleCoilRequest(1, 1, true),
                    ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 0, 1, byte.MaxValue, 0 }))
                },
                {
                    new WriteSingleCoilRequest(1, 1, true),
                    ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 0, 1, byte.MaxValue, 0 }))
                },
                {
                    new WriteSingleCoilRequest(1, 1, true),
                    ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 5, 0, 2, byte.MaxValue, 0 }))
                },
                {
                    new WriteSingleCoilRequest(1, 1, false),
                    ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 5, 0, 1, byte.MaxValue, 0 }))
                },
                {
                    new WriteSingleCoilRequest(1, 1, true),
                    ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 5, 0, 1, 0, 0 }))
                },
                {
                    new WriteSingleRegisterRequest(1, 1, ushort.MaxValue),
                    ModbusResponseFactory.CreateResponse <WriteSingleRegisterResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 0, 1, 0, 0 }))
                },
                {
                    new WriteSingleRegisterRequest(1, 1, ushort.MaxValue),
                    ModbusResponseFactory.CreateResponse <WriteSingleRegisterResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 0, 1, 0, 0 }))
                },
                {
                    new WriteSingleRegisterRequest(1, 1, ushort.MaxValue),
                    ModbusResponseFactory.CreateResponse <WriteSingleRegisterResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 6, 0, 2, 0, 0 }))
                },
                {
                    new WriteSingleRegisterRequest(1, 1, ushort.MaxValue),
                    ModbusResponseFactory.CreateResponse <WriteSingleRegisterResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 6, 0, 1, 0, 0 }))
                },
                {
                    new WriteMultipleCoilsRequest(1, 1, new bool[] { true }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 0, 1, 0, 1 }))
                },
                {
                    new WriteMultipleCoilsRequest(1, 1, new bool[] { true }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 0, 1, 0, 1 }))
                },
                {
                    new WriteMultipleCoilsRequest(1, 1, new bool[] { true }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 15, 0, 2, 0, 1 }))
                },
                {
                    new WriteMultipleCoilsRequest(1, 1, new bool[] { true }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleCoilsResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 15, 0, 1, 0, 2 }))
                },
                {
                    new WriteMultipleRegistersRequest(1, 1, new ushort[] { ushort.MaxValue }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 2, 1, 0, 1, 0, 1 }))
                },
                {
                    new WriteMultipleRegistersRequest(1, 1, new ushort[] { ushort.MaxValue }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 1, 0, 1, 0, 1 }))
                },
                {
                    new WriteMultipleRegistersRequest(1, 1, new ushort[] { ushort.MaxValue }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 16, 0, 2, 0, 1 }))
                },
                {
                    new WriteMultipleRegistersRequest(1, 1, new ushort[] { ushort.MaxValue }),
                    ModbusResponseFactory.CreateResponse <WriteMultipleRegistersResponse>(new ReadOnlySpan <byte>(new byte[] { 1, 16, 0, 1, 0, 2 }))
                }
            };

            return(theoryData);
        }
 public void CreateReadHoldingRegistersResponseThrowsOnFrameTooSmall(byte[] frame)
 {
     // Arrange/Act/Assert
     Assert.Throws <FormatException>(() => ModbusResponseFactory.CreateResponse <ReadHoldingRegistersResponse>(frame));
 }
 public void CreateWriteSingleCoilResponseThrowsOnFrameTooSmall(byte[] frame)
 {
     // Arrange/Act/Assert
     Assert.Throws <FormatException>(() =>
                                     ModbusResponseFactory.CreateResponse <WriteSingleCoilResponse>(frame));
 }
 public void CreateSlaveExceptionResponseThrowsOnFrameTooSmall()
 {
     // Arrange/Act/Assert
     Assert.Throws <FormatException>(() =>
                                     ModbusResponseFactory.CreateResponse <SlaveExceptionResponse>(new byte[] { 11, 129 }));
 }