This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
commit 18bb3f3a561e1d8d4a71712b7b3df0dfd6d50391 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Thu Jul 26 12:54:47 2018 +0200 modbus: fixed coil parsing --- .../java/modbus/netty/Plc4XModbusProtocol.java | 7 ++-- .../plc4x/java/modbus/ManualPlc4XModbusTest.java | 44 +++++++++++++++----- .../java/modbus/netty/Plc4XModbusProtocolTest.java | 47 +++++++++++----------- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java index b4914a8..769d17d 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java @@ -401,12 +401,13 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload, } byteBuf.readBytes(bytes); List<T> data = new LinkedList<>(); - for (int i = 0, j = 0; i < readRequestItem.getSize(); i++) { - if (i != 0 && i % 8 == 0) { + for (int i = 0, j = 0; data.size() < readRequestItem.getSize(); i++) { + if (i > 7) { // Every 8 Coils we need to increase the access j++; + i = 0; } - boolean coilSet = (1 << i & bytes[j]) == 1; + boolean coilSet = (bytes[j] & (1L << i)) != 0; byte coilFlag = coilSet ? (byte) 1 : (byte) 0; if (dataType == Boolean.class) { @SuppressWarnings("unchecked") diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualPlc4XModbusTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualPlc4XModbusTest.java index 36c5ff8..a37a702 100644 --- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualPlc4XModbusTest.java +++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualPlc4XModbusTest.java @@ -21,9 +21,12 @@ package org.apache.plc4x.java.modbus; import org.apache.plc4x.java.PlcDriverManager; import org.apache.plc4x.java.api.connection.PlcConnection; import org.apache.plc4x.java.api.connection.PlcReader; +import org.apache.plc4x.java.api.connection.PlcWriter; import org.apache.plc4x.java.api.messages.items.ReadResponseItem; import org.apache.plc4x.java.api.messages.specific.TypeSafePlcReadRequest; import org.apache.plc4x.java.api.messages.specific.TypeSafePlcReadResponse; +import org.apache.plc4x.java.api.messages.specific.TypeSafePlcWriteRequest; +import org.apache.plc4x.java.api.messages.specific.TypeSafePlcWriteResponse; import org.apache.plc4x.java.api.model.Address; import java.util.concurrent.CompletableFuture; @@ -42,16 +45,39 @@ public class ManualPlc4XModbusTest { try (PlcConnection plcConnection = new PlcDriverManager().getConnection(connectionUrl)) { System.out.println("PlcConnection " + plcConnection); - PlcReader reader = plcConnection.getReader().orElseThrow(() -> new RuntimeException("No Reader found")); + { + PlcReader reader = plcConnection.getReader().orElseThrow(() -> new RuntimeException("No Reader found")); - Address address = plcConnection.parseAddress("register:7"); - CompletableFuture<TypeSafePlcReadResponse<Integer>> response = reader - .read(new TypeSafePlcReadRequest<>(Integer.class, address)); - TypeSafePlcReadResponse<Integer> readResponse = response.get(); - System.out.println("Response " + readResponse); - ReadResponseItem<Integer> responseItem = readResponse.getResponseItem().orElseThrow(() -> new RuntimeException("No Item found")); - System.out.println("ResponseItem " + responseItem); - responseItem.getValues().stream().map(integer -> "Value: " + integer).forEach(System.out::println); + Address address = plcConnection.parseAddress("register:7"); + CompletableFuture<TypeSafePlcReadResponse<Integer>> response = reader + .read(new TypeSafePlcReadRequest<>(Integer.class, address)); + TypeSafePlcReadResponse<Integer> readResponse = response.get(); + System.out.println("Response " + readResponse); + ReadResponseItem<Integer> responseItem = readResponse.getResponseItem().orElseThrow(() -> new RuntimeException("No Item found")); + System.out.println("ResponseItem " + responseItem); + responseItem.getValues().stream().map(integer -> "Value: " + integer).forEach(System.out::println); + } + + { + PlcReader reader = plcConnection.getReader().orElseThrow(() -> new RuntimeException("No Reader found")); + + Address address = plcConnection.parseAddress("coil:1"); + CompletableFuture<TypeSafePlcReadResponse<Integer>> response = reader + .read(new TypeSafePlcReadRequest<>(Integer.class, address)); + TypeSafePlcReadResponse<Integer> readResponse = response.get(); + System.out.println("Response " + readResponse); + ReadResponseItem<Integer> responseItem = readResponse.getResponseItem().orElseThrow(() -> new RuntimeException("No Item found")); + System.out.println("ResponseItem " + responseItem); + responseItem.getValues().stream().map(integer -> "Value: " + integer).forEach(System.out::println); + } + + { + PlcWriter writer = plcConnection.getWriter().orElseThrow(() -> new RuntimeException("No Writer found")); + Address address = plcConnection.parseAddress("coil:1"); + CompletableFuture<TypeSafePlcWriteResponse<Integer>> write = writer.write(new TypeSafePlcWriteRequest<>(Integer.class, address, 1)); + TypeSafePlcWriteResponse<Integer> writeResponse = write.get(); + System.out.println("Response " + writeResponse); + } } catch (Exception e) { e.printStackTrace(); System.exit(1); diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java index f28cb69..01b8d75 100644 --- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java +++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java @@ -24,7 +24,6 @@ import com.digitalpetri.modbus.requests.*; import com.digitalpetri.modbus.responses.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.plc4x.java.api.messages.*; import org.apache.plc4x.java.api.messages.items.ReadResponseItem; @@ -51,7 +50,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.apache.plc4x.java.base.protocol.Plc4XSupportedDataTypes.defaultAssert; -import static org.apache.plc4x.java.base.protocol.Plc4XSupportedDataTypes.streamOfLittleEndianDataTypePairs; +import static org.apache.plc4x.java.base.protocol.Plc4XSupportedDataTypes.streamOfBigEndianDataTypePairs; import static org.apache.plc4x.java.base.util.Assert.assertByteEquals; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; @@ -95,7 +94,7 @@ public class Plc4XModbusProtocolTest { @Parameterized.Parameters(name = "{index} Type:{0} {3} {5}") public static Collection<Object[]> data() { - return streamOfLittleEndianDataTypePairs() + return streamOfBigEndianDataTypePairs() .map(pair -> Stream.of( ImmutablePair.of( new PlcRequestContainer<>( @@ -103,7 +102,9 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(pair.getLeft().getClass(), CoilModbusAddress.of("coil:1")) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new ReadCoilsResponse(Unpooled.wrappedBuffer(pair.getRight()))) + // Coils are a bit different so the only know 1 or 0. So we know streamOfBigEndianDataTypePairs are + // all positive so we return one byte with the first bit set + new ModbusTcpPayload((short) 0, (short) 0, new ReadCoilsResponse(Unpooled.wrappedBuffer(new byte[]{(byte) 0x1}))) ), ImmutablePair.of( new PlcRequestContainer<>( @@ -111,7 +112,9 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(CoilModbusAddress.of("coil:1"), pair.getLeft()) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleCoilResponse(1, pair.getRight()[0])) + // Coils are a bit different so the only know 1 or 0. So we know streamOfBigEndianDataTypePairs are + // all positive so we return one byte with the first bit set + new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleCoilResponse(1, 1)) ), /* Read request no supported on maskwrite so how to handle? ImmutablePair.of( @@ -136,7 +139,9 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(pair.getLeft().getClass(), ReadDiscreteInputsModbusAddress.of("readdiscreteinputs:1")) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new ReadDiscreteInputsResponse(Unpooled.wrappedBuffer(pair.getRight()))) + // Coils are a bit different so the only know 1 or 0. So we know streamOfBigEndianDataTypePairs are + // all positive so we return one byte with the first bit set + new ModbusTcpPayload((short) 0, (short) 0, new ReadDiscreteInputsResponse(Unpooled.wrappedBuffer(new byte[]{(byte) 0x01}))) ), ImmutablePair.of( new PlcRequestContainer<>( @@ -144,7 +149,7 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(pair.getLeft().getClass(), ReadHoldingRegistersModbusAddress.of("readholdingregisters:1")) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new ReadHoldingRegistersResponse(Unpooled.wrappedBuffer(evenUp(pair.getRight())))) + new ModbusTcpPayload((short) 0, (short) 0, new ReadHoldingRegistersResponse(Unpooled.wrappedBuffer(cutRegister(pair.getRight())))) ), ImmutablePair.of( new PlcRequestContainer<>( @@ -152,7 +157,7 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(pair.getLeft().getClass(), ReadInputRegistersModbusAddress.of("readinputregisters:1")) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new ReadInputRegistersResponse(Unpooled.wrappedBuffer(evenUp(pair.getRight())))) + new ModbusTcpPayload((short) 0, (short) 0, new ReadInputRegistersResponse(Unpooled.wrappedBuffer(cutRegister(pair.getRight())))) ), ImmutablePair.of( new PlcRequestContainer<>( @@ -176,19 +181,15 @@ public class Plc4XModbusProtocolTest { .builder() .addItem(RegisterModbusAddress.of("register:1"), pair.getLeft()) .build(), new CompletableFuture<>()), - new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleRegisterResponse(1, pair.getRight()[0])) + new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleRegisterResponse(1, cutRegister(pair.getRight())[0])) ) )) .flatMap(stream -> stream) .map(pair -> new Object[]{pair.left.getRequest().getRequestItem().orElseThrow(IllegalStateException::new).getDatatype().getSimpleName(), pair.left, pair.left.getResponseFuture(), pair.left.getRequest().getClass().getSimpleName(), pair.right, pair.right.getModbusPdu().getClass().getSimpleName()}).collect(Collectors.toList()); } - private static byte[] evenUp(byte[] bytes) { - if (bytes.length % 2 == 0) { - return bytes; - } else { - return ArrayUtils.insert(0, bytes, (byte) 0x0); - } + private static byte[] cutRegister(byte[] right) { + return new byte[]{right.length > 1 ? right[right.length - 2] : 0x0, right[right.length - 1]}; } @Before @@ -371,35 +372,35 @@ public class Plc4XModbusProtocolTest { ResponseItem responseItem = (ResponseItem) plcResponse.getResponseItem().get(); LOGGER.info("ResponseItem {}", responseItem); ModbusPdu modbusPdu = modbusTcpPayload.getModbusPdu(); - if (modbusPdu instanceof MaskWriteRegisterRequest) { + if (modbusPdu instanceof MaskWriteRegisterResponse) { WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem; assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode()); - } else if (modbusPdu instanceof ReadCoilsRequest) { + } else if (modbusPdu instanceof ReadCoilsResponse) { ReadResponseItem readResponseItem = (ReadResponseItem) responseItem; Object value = readResponseItem.getValues().get(0); defaultAssert(value); - } else if (modbusPdu instanceof ReadDiscreteInputsRequest) { + } else if (modbusPdu instanceof ReadDiscreteInputsResponse) { ReadResponseItem readResponseItem = (ReadResponseItem) responseItem; Object value = readResponseItem.getValues().get(0); defaultAssert(value); - } else if (modbusPdu instanceof ReadHoldingRegistersRequest) { + } else if (modbusPdu instanceof ReadHoldingRegistersResponse) { ReadResponseItem readResponseItem = (ReadResponseItem) responseItem; Object value = readResponseItem.getValues().get(0); defaultAssert(value); - } else if (modbusPdu instanceof ReadInputRegistersRequest) { + } else if (modbusPdu instanceof ReadInputRegistersResponse) { ReadResponseItem readResponseItem = (ReadResponseItem) responseItem; Object value = readResponseItem.getValues().get(0); defaultAssert(value); - } else if (modbusPdu instanceof WriteMultipleCoilsRequest) { + } else if (modbusPdu instanceof WriteMultipleCoilsResponse) { WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem; assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode()); - } else if (modbusPdu instanceof WriteMultipleRegistersRequest) { + } else if (modbusPdu instanceof WriteMultipleRegistersResponse) { WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem; assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode()); } else if (modbusPdu instanceof WriteSingleCoilResponse) { WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem; assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode()); - } else if (modbusPdu instanceof WriteSingleRegisterRequest) { + } else if (modbusPdu instanceof WriteSingleRegisterResponse) { WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem; assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode()); }