You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2018/07/05 15:42:02 UTC
[incubator-plc4x] branch master updated: added Test for
Plc4XModbusProtocol and fixed several Bugs.
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
The following commit(s) were added to refs/heads/master by this push:
new 22d5106 added Test for Plc4XModbusProtocol and fixed several Bugs.
22d5106 is described below
commit 22d5106948d4723a7077d40e84ff4c63c554fabf
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Jul 5 17:41:56 2018 +0200
added Test for Plc4XModbusProtocol and fixed several Bugs.
---
.../modbus/connection/BaseModbusPlcConnection.java | 4 +-
.../plc4x/java/modbus/model/CoilModbusAddress.java | 2 +-
.../model/MaskWriteRegisterModbusAddress.java | 2 +-
.../model/ReadDiscreteInputsModbusAddress.java | 2 +-
.../model/ReadHoldingRegistersModbusAddress.java | 2 +-
.../model/ReadInputRegistersModbusAddress.java | 2 +-
...sterAddress.java => RegisterModbusAddress.java} | 10 +-
.../java/modbus/netty/Plc4XModbusProtocol.java | 42 ++-
.../connection/ModbusSerialPlcConnectionTest.java | 2 +-
.../connection/ModbusTcpPlcConnectionTests.java | 2 +-
.../java/modbus/netty/Plc4XModbusProtocolTest.java | 294 +++++++++++++++++++--
11 files changed, 317 insertions(+), 47 deletions(-)
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java
index 0056363..6be492d 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java
@@ -68,8 +68,8 @@ public abstract class BaseModbusPlcConnection extends AbstractPlcConnection impl
return ReadInputRegistersModbusAddress.of(addressString);
} else if (CoilModbusAddress.ADDRESS_PATTERN.matcher(addressString).matches()) {
return CoilModbusAddress.of(addressString);
- } else if (RegisterAddress.ADDRESS_PATTERN.matcher(addressString).matches()) {
- return RegisterAddress.of(addressString);
+ } else if (RegisterModbusAddress.ADDRESS_PATTERN.matcher(addressString).matches()) {
+ return RegisterModbusAddress.of(addressString);
}
return null;
}
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusAddress.java
index 414c968..19681b0 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusAddress.java
@@ -34,7 +34,7 @@ public class CoilModbusAddress extends ModbusAddress {
public static CoilModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
return new CoilModbusAddress(address);
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/MaskWriteRegisterModbusAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/MaskWriteRegisterModbusAddress.java
index fe61796..1709799 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/MaskWriteRegisterModbusAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/MaskWriteRegisterModbusAddress.java
@@ -40,7 +40,7 @@ public class MaskWriteRegisterModbusAddress extends ModbusAddress {
public static MaskWriteRegisterModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
int andMask = Integer.valueOf(matcher.group("andMask"));
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusAddress.java
index 2433e26..7adf4e2 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusAddress.java
@@ -34,7 +34,7 @@ public class ReadDiscreteInputsModbusAddress extends ModbusAddress {
public static ReadDiscreteInputsModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
return new ReadDiscreteInputsModbusAddress(address);
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusAddress.java
index 4d222f8..847cb29 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusAddress.java
@@ -34,7 +34,7 @@ public class ReadHoldingRegistersModbusAddress extends ModbusAddress {
public static ReadHoldingRegistersModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
return new ReadHoldingRegistersModbusAddress(address);
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusAddress.java
index 36172ab..663fbe1 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusAddress.java
@@ -34,7 +34,7 @@ public class ReadInputRegistersModbusAddress extends ModbusAddress {
public static ReadInputRegistersModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
return new ReadInputRegistersModbusAddress(address);
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterAddress.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusAddress.java
similarity index 84%
rename from plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterAddress.java
rename to plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusAddress.java
index 69fe451..ac112d8 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterAddress.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusAddress.java
@@ -24,20 +24,20 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
// TODO: Default to {@link ReadHoldingRegistersModbusAddress}
-public class RegisterAddress extends ModbusAddress {
+public class RegisterModbusAddress extends ModbusAddress {
public static final Pattern ADDRESS_PATTERN = Pattern.compile("register:" + ModbusAddress.ADDRESS_PATTERN);
- protected RegisterAddress(int address) {
+ protected RegisterModbusAddress(int address) {
super(address);
}
- public static RegisterAddress of(String addressString) {
+ public static RegisterModbusAddress of(String addressString) {
Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
if (!matcher.matches()) {
- throw new PlcRuntimeException(addressString + " doesn't match" + ADDRESS_PATTERN);
+ throw new PlcRuntimeException(addressString + " doesn't match " + ADDRESS_PATTERN);
}
int address = Integer.valueOf(matcher.group("address"));
- return new RegisterAddress(address);
+ return new RegisterModbusAddress(address);
}
}
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 8f751fa..c5b9698 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
@@ -37,6 +37,7 @@ import org.apache.plc4x.java.modbus.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -79,24 +80,23 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
ModbusAddress address = (ModbusAddress) writeRequestItem.getAddress();
ModbusPdu modbusRequest;
- if (address instanceof RegisterAddress) {
- RegisterAddress registerAddress = (RegisterAddress) address;
+ if (address instanceof RegisterModbusAddress) {
+ RegisterModbusAddress registerModbusAddress = (RegisterModbusAddress) address;
if (quantity > 1) {
byte[] bytesToWrite = produceRegisterValue(writeRequestItem.getValues());
- modbusRequest = new WriteMultipleRegistersRequest(registerAddress.getAddress(), quantity, bytesToWrite);
+ modbusRequest = new WriteMultipleRegistersRequest(registerModbusAddress.getAddress(), quantity, bytesToWrite);
} else {
byte[] register = produceRegisterValue(writeRequestItem.getValues());
int intToWrite = register[0] << 8 | register[1];
- modbusRequest = new WriteSingleRegisterRequest(registerAddress.getAddress(), intToWrite);
+ modbusRequest = new WriteSingleRegisterRequest(registerModbusAddress.getAddress(), intToWrite);
}
} else if (address instanceof CoilModbusAddress) {
CoilModbusAddress coilModbusAddress = (CoilModbusAddress) address;
if (quantity > 1) {
- byte[] bytesToWrite = produceCoilValue(writeRequestItem.getValues());
+ byte[] bytesToWrite = produceCoilValues(writeRequestItem.getValues());
modbusRequest = new WriteMultipleCoilsRequest(coilModbusAddress.getAddress(), quantity, bytesToWrite);
} else {
- byte[] coil = produceCoilValue(writeRequestItem.getValues());
- boolean booleanToWrite = (coil[0] >> 8) == 1;
+ boolean booleanToWrite = produceCoilValue(writeRequestItem.getValues());
modbusRequest = new WriteSingleCoilRequest(coilModbusAddress.getAddress(), booleanToWrite);
}
} else {
@@ -122,9 +122,9 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
if (address instanceof CoilModbusAddress) {
CoilModbusAddress coilModbusAddress = (CoilModbusAddress) address;
modbusRequest = new ReadCoilsRequest(coilModbusAddress.getAddress(), quantity);
- } else if (address instanceof RegisterAddress) {
- RegisterAddress registerAddress = (RegisterAddress) address;
- modbusRequest = new ReadHoldingRegistersRequest(registerAddress.getAddress(), quantity);
+ } else if (address instanceof RegisterModbusAddress) {
+ RegisterModbusAddress registerModbusAddress = (RegisterModbusAddress) address;
+ modbusRequest = new ReadHoldingRegistersRequest(registerModbusAddress.getAddress(), quantity);
} else if (address instanceof ReadDiscreteInputsModbusAddress) {
ReadDiscreteInputsModbusAddress readDiscreteInputsModbusAddress = (ReadDiscreteInputsModbusAddress) address;
modbusRequest = new ReadDiscreteInputsRequest(readDiscreteInputsModbusAddress.getAddress(), quantity);
@@ -151,7 +151,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
short transactionId = msg.getTransactionId();
PlcRequestContainer<PlcRequest, PlcResponse> plcRequestContainer = requestsMap.get(transactionId);
if (plcRequestContainer == null) {
- throw new PlcProtocolException("Unrelated payload received" + msg);
+ throw new PlcProtocolException("Unrelated payload received. [transactionId: " + msg.getTransactionId() + ", unitId: " + msg.getUnitId() + ", modbusPdu: " + msg.getModbusPdu() + "]");
}
// TODO: only single Item supported for now
@@ -246,7 +246,16 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
////////////////////////////////////////////////////////////////////////////////
// Encoding helpers.
////////////////////////////////////////////////////////////////////////////////
- private byte[] produceCoilValue(List<?> values) throws PlcProtocolException {
+
+ private boolean produceCoilValue(List<?> values) throws PlcProtocolException {
+ if (values.size() != 1) {
+ throw new PlcProtocolException("Only one value allowed");
+ }
+ Byte multiCoil = produceCoilValues(values)[0];
+ return multiCoil != 0;
+ }
+
+ private byte[] produceCoilValues(List<?> values) throws PlcProtocolException {
List<Byte> coils = new LinkedList<>();
Byte actualCoil = 0;
int i = 7;
@@ -289,6 +298,10 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
i = 8;
}
}
+ if (coils.isEmpty()) {
+ // We only have one coil
+ return new byte[]{actualCoil};
+ }
// TODO: ensure we have a least (quantity + 7) / 8 = N bytes
return ArrayUtils.toPrimitive(coils.toArray(new Byte[0]));
}
@@ -309,7 +322,7 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
}
buffer.writeBytes(bytes);
} else if (value.getClass() == Short.class) {
- buffer.writeShort((int) value);
+ buffer.writeShort((short) value);
} else if (value.getClass() == Integer.class) {
if ((int) value > Integer.MAX_VALUE) {
throw new PlcProtocolException("Value to high to fit into register: " + value);
@@ -331,6 +344,9 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
private List produceCoilValueList(RequestItem requestItem, Class datatype, ByteBuf byteBuf) {
ReadRequestItem readRequestItem = (ReadRequestItem) requestItem;
byte[] bytes = new byte[byteBuf.readableBytes()];
+ if (bytes.length < 1) {
+ return Collections.emptyList();
+ }
byteBuf.readBytes(bytes);
List data = new LinkedList();
for (int i = 0, j = 0; i < readRequestItem.getSize(); i++) {
diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusSerialPlcConnectionTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusSerialPlcConnectionTest.java
index 4339c42..ce2fe47 100644
--- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusSerialPlcConnectionTest.java
+++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusSerialPlcConnectionTest.java
@@ -126,7 +126,7 @@ public class ModbusSerialPlcConnectionTest {
@Test
public void parseRegisterAddress() {
try {
- RegisterAddress address = (RegisterAddress) SUT.parseAddress("0/1");
+ RegisterModbusAddress address = (RegisterModbusAddress) SUT.parseAddress("0/1");
assertEquals(address.getAddress(), 0);
} catch (IllegalArgumentException exception) {
fail("valid data block address");
diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnectionTests.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnectionTests.java
index 10293e3..3640e34 100644
--- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnectionTests.java
+++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnectionTests.java
@@ -124,7 +124,7 @@ public class ModbusTcpPlcConnectionTests {
@Test
public void parseRegisterAddress() {
try {
- RegisterAddress address = (RegisterAddress) SUT.parseAddress("register:0");
+ RegisterModbusAddress address = (RegisterModbusAddress) SUT.parseAddress("register:0");
assertEquals(address.getAddress(), 0);
} catch (IllegalArgumentException exception) {
fail("valid data block address");
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 5926373..685efba 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
@@ -18,32 +18,286 @@
*/
package org.apache.plc4x.java.modbus.netty;
-import org.apache.commons.lang3.reflect.MethodUtils;
+import com.digitalpetri.modbus.ModbusPdu;
+import com.digitalpetri.modbus.codec.ModbusTcpPayload;
+import com.digitalpetri.modbus.requests.*;
+import com.digitalpetri.modbus.responses.*;
+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;
+import org.apache.plc4x.java.api.messages.items.ResponseItem;
+import org.apache.plc4x.java.modbus.model.*;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import java.util.Arrays;
-import java.util.BitSet;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
+@RunWith(Parameterized.class)
public class Plc4XModbusProtocolTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(Plc4XModbusProtocolTest.class);
+
+ public static final Calendar calenderInstance = Calendar.getInstance();
+
+ private Plc4XModbusProtocol SUT;
+
+ @Parameterized.Parameter
+ public String payloadClazzName;
+
+ @Parameterized.Parameter(1)
+ public PlcRequestContainer<PlcRequest, PlcResponse> plcRequestContainer;
+
+ @Parameterized.Parameter(2)
+ public CompletableFuture completableFuture;
+
+ @Parameterized.Parameter(3)
+ public String plcRequestContainerClassName;
+
+ @Parameterized.Parameter(4)
+ public ModbusTcpPayload modbusTcpPayload;
+
+ @Parameterized.Parameter(5)
+ public String modbusPduName;
+
+ @Parameterized.Parameters(name = "{index} Type:{0} {3} {5}")
+ public static Collection<Object[]> data() {
+ return Stream.of(
+ Boolean.class,
+ Byte.class,
+ Short.class,
+ //Calendar.class,
+ //Float.class,
+ Integer.class //,
+ //String.class
+ )
+ .map(clazz -> {
+ if (clazz == Boolean.class) {
+ return ImmutablePair.of(Boolean.TRUE, new byte[]{0x01});
+ } else if (clazz == Byte.class) {
+ return ImmutablePair.of(Byte.valueOf("1"), new byte[]{0x1});
+ } else if (clazz == Short.class) {
+ return ImmutablePair.of(Short.valueOf("1"), new byte[]{0x1, 0x0});
+ } else if (clazz == Calendar.class) {
+ return ImmutablePair.of(calenderInstance, new byte[]{0x0, 0x0, 0x0, 0x0, 0x4, 0x3, 0x2, 0x1});
+ } else if (clazz == Float.class) {
+ return ImmutablePair.of(Float.valueOf("1"), new byte[]{0x0, 0x0, (byte) 0x80, 0x3F});
+ } else if (clazz == Integer.class) {
+ return ImmutablePair.of(Integer.valueOf("1"), new byte[]{0x1, 0x0, 0x0, 0x0});
+ } else if (clazz == String.class) {
+ return ImmutablePair.of(String.valueOf("Hello World!"), new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00});
+ } else {
+ throw new IllegalArgumentException("Unmapped type " + clazz);
+ }
+ })
+ .map(pair -> Stream.of(
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcReadRequest
+ .builder()
+ .addItem(pair.left.getClass(), CoilModbusAddress.of("coil:1"))
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new ReadCoilsResponse(Unpooled.wrappedBuffer(pair.right)))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcReadRequest
+ .builder()
+ .addItem(pair.left.getClass(), ReadDiscreteInputsModbusAddress.of("readdiscreteinputs:1"))
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new ReadDiscreteInputsResponse(Unpooled.wrappedBuffer(pair.right)))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcReadRequest
+ .builder()
+ .addItem(pair.left.getClass(), ReadHoldingRegistersModbusAddress.of("readholdingregisters:1"))
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new ReadHoldingRegistersResponse(Unpooled.wrappedBuffer(evenUp(pair.right))))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcReadRequest
+ .builder()
+ .addItem(pair.left.getClass(), ReadInputRegistersModbusAddress.of("readinputregisters:1"))
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new ReadInputRegistersResponse(Unpooled.wrappedBuffer(evenUp(pair.right))))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcWriteRequest
+ .builder()
+ .addItem((Class) pair.left.getClass(), CoilModbusAddress.of("coil:1"), pair.left, pair.left, pair.left)
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new WriteMultipleCoilsResponse(1, 3))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcWriteRequest
+ .builder()
+ .addItem((Class) pair.left.getClass(), RegisterModbusAddress.of("register:1"), pair.left, pair.left, pair.left)
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new WriteMultipleCoilsResponse(1, 3))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcWriteRequest
+ .builder()
+ .addItem(CoilModbusAddress.of("coil:1"), pair.left)
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleCoilResponse(1, pair.right[0]))
+ ),
+ ImmutablePair.of(
+ new PlcRequestContainer<>(
+ PlcWriteRequest
+ .builder()
+ .addItem(RegisterModbusAddress.of("register:1"), pair.left)
+ .build(), new CompletableFuture<>()),
+ new ModbusTcpPayload((short) 0, (short) 0, new WriteSingleCoilResponse(1, pair.right[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);
+ }
+ }
+
+ @Before
+ public void setUp() {
+ SUT = new Plc4XModbusProtocol();
+ }
+
+ @Test
+ public void encode() throws Exception {
+ ArrayList<Object> out = new ArrayList<>();
+ SUT.encode(null, plcRequestContainer, out);
+ assertThat(out, hasSize(1));
+ assertThat(out.get(0), instanceOf(ModbusTcpPayload.class));
+ ModbusTcpPayload modbusTcpPayload = (ModbusTcpPayload) out.get(0);
+ ModbusPdu modbusPdu = modbusTcpPayload.getModbusPdu();
+ if (modbusPdu instanceof MaskWriteRegisterRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadCoilsRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadDiscreteInputsRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadHoldingRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadInputRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteMultipleCoilsRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteMultipleRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteSingleCoilRequest) {
+ WriteSingleCoilRequest writeSingleCoilRequest = (WriteSingleCoilRequest) modbusPdu;
+ int address = writeSingleCoilRequest.getAddress();
+ assertThat(address, equalTo(1));
+ int value = writeSingleCoilRequest.getValue();
+ boolean coilValue = value == 0xFF00;
+ if (payloadClazzName.equals(Boolean.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(Byte.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(Short.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(Calendar.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(Float.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(Integer.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ } else if (payloadClazzName.equals(String.class.getSimpleName())) {
+ assertThat(coilValue, equalTo(true));
+ }
+ } else if (modbusPdu instanceof WriteSingleRegisterRequest) {
+ // TODO: implement me
+ }
+ }
+
@Test
- public void coilEncoding() throws Exception {
- byte[] bytes = (byte[]) MethodUtils.invokeMethod(new Plc4XModbusProtocol(), true, "produceCoilValue", Arrays.asList(false, false, true, false, false, false, true, false));
- assertSame(1, bytes.length);
- String s1 = String.format("%8s", Integer.toBinaryString(bytes[0] & 0xFF)).replace(' ', '0');
- assertEquals("00100010", s1);
-
- // TODO: just for reference we could use a bitset too
- BitSet bitSet = new BitSet(8);
- bitSet.set(1);
- bitSet.set(5);
- byte[] bytes1 = bitSet.toByteArray();
- assertSame(1, bytes1.length);
-
- String s2 = String.format("%8s", Integer.toBinaryString(bytes1[0] & 0xFF)).replace(' ', '0');
- assertEquals("00100010", s2);
+ public void decode() throws Exception {
+ ArrayList<Object> in = new ArrayList<>();
+ SUT.encode(null, plcRequestContainer, in);
+ assertThat(in, hasSize(1));
+ syncInvoiceId();
+ ArrayList<Object> out = new ArrayList<>();
+ SUT.decode(null, modbusTcpPayload, out);
+ assertThat(out, hasSize(0));
+ LOGGER.info("PlcRequestContainer {}", plcRequestContainer);
+ PlcResponse plcResponse = plcRequestContainer.getResponseFuture().get();
+ ResponseItem responseItem = (ResponseItem) plcResponse.getResponseItem().get();
+ LOGGER.info("ResponseItem {}", responseItem);
+ ModbusPdu modbusPdu = modbusTcpPayload.getModbusPdu();
+ if (modbusPdu instanceof MaskWriteRegisterRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadCoilsRequest) {
+ ReadResponseItem readResponseItem = (ReadResponseItem) responseItem;
+ Object value = readResponseItem.getValues().get(0);
+ if (payloadClazzName.equals(Boolean.class.getSimpleName())) {
+ assertThat(value, equalTo(Boolean.TRUE));
+ } else if (payloadClazzName.equals(Byte.class.getSimpleName())) {
+ assertThat(value, equalTo(Byte.valueOf("1")));
+ } else if (payloadClazzName.equals(Short.class.getSimpleName())) {
+ assertThat(value, equalTo(Short.valueOf("1")));
+ } else if (payloadClazzName.equals(Calendar.class.getSimpleName())) {
+ assertThat(value, equalTo(calenderInstance));
+ } else if (payloadClazzName.equals(Float.class.getSimpleName())) {
+ assertThat(value, equalTo(Float.valueOf("1")));
+ } else if (payloadClazzName.equals(Integer.class.getSimpleName())) {
+ assertThat(value, equalTo(Integer.valueOf("1")));
+ } else if (payloadClazzName.equals(String.class.getSimpleName())) {
+ assertThat(value, equalTo(String.valueOf("Hello World!")));
+ }
+ } else if (modbusPdu instanceof ReadDiscreteInputsRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadHoldingRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof ReadInputRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteMultipleCoilsRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteMultipleRegistersRequest) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteSingleCoilResponse) {
+ // TODO: implement me
+ } else if (modbusPdu instanceof WriteSingleRegisterRequest) {
+ // TODO: implement me
+ }
+ }
+
+ private void syncInvoiceId() throws Exception {
+ Field transactionId = SUT.getClass().getDeclaredField("transactionId");
+ transactionId.setAccessible(true);
+ AtomicInteger correlationBuilder = (AtomicInteger) transactionId.get(SUT);
+
+ Field invokeIdField = ModbusTcpPayload.class.getDeclaredField("transactionId");
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(invokeIdField, invokeIdField.getModifiers() & ~Modifier.FINAL);
+ invokeIdField.setAccessible(true);
+ invokeIdField.set(modbusTcpPayload, (short) (correlationBuilder.get() - 1));
}
}
\ No newline at end of file