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); }
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()); }
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); }
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); }
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 })); }