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/08/02 14:35:40 UTC
[incubator-plc4x] branch master updated: Added byte[] and Byte[]
implementation to modbus.
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 972c532 Added byte[] and Byte[] implementation to modbus.
972c532 is described below
commit 972c532ad78269424a2b15dc72f6dc57f571488f
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Aug 2 16:35:30 2018 +0200
Added byte[] and Byte[] implementation to modbus.
---
.../base/protocol/Plc4XSupportedDataTypes.java | 40 ++++++++++++++++-
.../java/modbus/netty/Plc4XModbusProtocol.java | 39 +++++++++++++---
.../java/modbus/netty/Plc4XModbusProtocolTest.java | 52 +++++++++++++++-------
3 files changed, 108 insertions(+), 23 deletions(-)
diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java
index f3ee07b..4b1ca7e 100644
--- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java
+++ b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.tuple.Pair;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
+import java.util.function.Function;
import java.util.stream.Stream;
import static org.hamcrest.Matchers.equalTo;
@@ -58,6 +59,10 @@ public class Plc4XSupportedDataTypes {
byte[] littleEndianBytes = pair.getByteRepresentation();
byte[] bigEndianBytes = ArrayUtils.clone(littleEndianBytes);
ArrayUtils.reverse(bigEndianBytes);
+ if (clazz == byte[].class || clazz == Byte[].class) {
+ // For Byte[] or byte[] values put in should be exactly how supplied.
+ ArrayUtils.reverse(bigEndianBytes);
+ }
bigEndianMap.put(clazz, DataTypePair.of(serializable, bigEndianBytes));
});
}
@@ -149,7 +154,17 @@ public class Plc4XSupportedDataTypes {
* @param actualValue the value to check.
*/
public static void defaultAssert(Object actualValue) {
- littleEndianMap.values().forEach(pair -> assertPayloadDependentEquals(actualValue, pair.getValue()));
+ defaultAssert(actualValue, dataTypePair -> dataTypePair);
+ }
+
+ /**
+ * A method which compares a value against a well known default.
+ *
+ * @param actualValue the value to check.
+ * @param customMapper a mapper which manipulates values before they get checked.
+ */
+ public static void defaultAssert(Object actualValue, Function<? super DataTypePair<?>, ? extends DataTypePair<?>> customMapper) {
+ littleEndianMap.values().stream().map(customMapper).forEach(pair -> assertPayloadDependentEquals(actualValue, pair.getValue()));
}
private static void assertPayloadDependentEquals(Object actual, Object expected) {
@@ -196,5 +211,28 @@ public class Plc4XSupportedDataTypes {
return ArrayUtils.clone(dataTypePair.getRight());
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DataTypePair)) {
+ return false;
+ }
+ DataTypePair<?> that = (DataTypePair<?>) o;
+ return Objects.equals(dataTypePair, that.dataTypePair);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(dataTypePair);
+ }
+
+ @Override
+ public String toString() {
+ return "DataTypePair{" +
+ "dataTypePair=" + dataTypePair +
+ '}';
+ }
}
}
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 3d5a1f6..d153b36 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
@@ -260,12 +260,13 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
!(value instanceof Boolean)
&& !(value instanceof Byte)
&& !(value instanceof byte[])
+ && !(value instanceof Byte[])
&& !(value instanceof Short)
&& !(value instanceof Integer)
&& !(value instanceof BigInteger)
&& !(value instanceof Float)
&& !(value instanceof Double)
- ) {
+ ) {
throw new PlcRuntimeException("Unsupported datatype detected " + value.getClass());
}
}
@@ -279,16 +280,16 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
if (values.size() != 1) {
throw new PlcProtocolException("Only one value allowed");
}
- Byte multiCoil = produceCoilValues(values)[0];
+ byte multiCoil = produceCoilValues(values)[0];
return multiCoil != 0;
}
private byte[] produceCoilValues(List<?> values) throws PlcProtocolException {
List<Byte> coils = new LinkedList<>();
- Byte actualCoil = 0;
+ byte actualCoil = 0;
int i = 7;
for (Object value : values) {
- boolean coilSet = false;
+ final boolean coilSet;
if (value.getClass() == Boolean.class) {
coilSet = (Boolean) value;
} else if (value.getClass() == Byte.class) {
@@ -299,9 +300,19 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
} else if (value.getClass() == byte[].class) {
byte[] bytes = (byte[]) value;
if (bytes.length != 1) {
- throw new PlcProtocolException("Only exactly one byte is allowed: " + bytes.length);
+ throw new PlcProtocolException("Exactly one byte is allowed: " + bytes.length);
}
- byte byteValue = bytes[1];
+ byte byteValue = bytes[0];
+ if (byteValue > 1) {
+ throw new PlcProtocolException("Value to high to fit into Byte: " + value);
+ }
+ coilSet = byteValue == 1;
+ } else if (value.getClass() == Byte[].class) {
+ Byte[] bytes = (Byte[]) value;
+ if (bytes.length != 1) {
+ throw new PlcProtocolException("Exactly one byte is allowed: " + bytes.length);
+ }
+ byte byteValue = bytes[0];
if (byteValue > 1) {
throw new PlcProtocolException("Value to high to fit into Byte: " + value);
}
@@ -354,9 +365,15 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
} else if (value.getClass() == byte[].class) {
byte[] bytes = (byte[]) value;
if (bytes.length != 2) {
- throw new PlcProtocolException("Only exactly two bytes are allowed: " + bytes.length);
+ throw new PlcProtocolException("Exactly two bytes are allowed: " + bytes.length);
}
buffer.writeBytes(bytes);
+ } else if (value.getClass() == Byte[].class) {
+ Byte[] bytes = (Byte[]) value;
+ if (bytes.length != 2) {
+ throw new PlcProtocolException("Exactly two bytes are allowed: " + bytes.length);
+ }
+ buffer.writeBytes(ArrayUtils.toPrimitive(bytes));
} else if (value.getClass() == Short.class) {
if ((short) value < 0) {
throw new PlcProtocolException("Only positive values are supported for Short: " + value);
@@ -447,6 +464,10 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
data.add(itemToBeAdded);
} else if (dataType == byte[].class) {
data.add((T) new byte[]{coilFlag});
+ } else if (dataType == Byte[].class) {
+ @SuppressWarnings("unchecked")
+ T itemToBeAdded = (T) new Byte[]{coilFlag};
+ data.add(itemToBeAdded);
} else if (dataType == Short.class) {
@SuppressWarnings("unchecked")
T itemToBeAdded = (T) Short.valueOf(coilFlag);
@@ -499,6 +520,10 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec<ModbusTcpPayload,
} else if (dataType == byte[].class) {
T itemToBeAdded = (T) register;
data.add(itemToBeAdded);
+ } else if (dataType == Byte[].class) {
+ @SuppressWarnings("unchecked")
+ T itemToBeAdded = (T) ArrayUtils.toObject(register);
+ data.add(itemToBeAdded);
} else if (dataType == Short.class) {
if (intValue > Short.MAX_VALUE) {
throw new PlcProtocolException("Value to high to fit into Short: " + intValue);
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 5adea46..7144720 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
@@ -71,9 +71,7 @@ public class Plc4XModbusProtocolTest {
// TODO: implement these types
private List<String> notYetSupportedDataType = Stream.of(
GregorianCalendar.class,
- String.class,
- byte[].class,
- Byte[].class
+ String.class
).map(Class::getSimpleName).collect(Collectors.toList());
@Parameterized.Parameter
@@ -109,17 +107,17 @@ public class Plc4XModbusProtocolTest {
})
.map(dataTypePair -> Stream.of(
producePair(dataTypePair.getDataTypeClass(), CoilModbusAddress.of("coil:1"), new ReadCoilsResponse(Unpooled.wrappedBuffer(new byte[]{(byte) 0x1}))),
- producePair(CoilModbusAddress.of("coil:1"), new WriteSingleCoilResponse(1, 1), dataTypePair.getValue()),
+ producePair(CoilModbusAddress.of("coil:1"), new WriteSingleCoilResponse(1, 1), mapDataTypePairForCoil(dataTypePair).getValue()),
/* Read request no supported on maskwrite so how to handle?
producePair(pair.getDataTypeClass(), MaskWriteRegisterModbusAddress.of("maskwrite:1/1/2"), new MaskWriteRegisterResponse(1, 1, 2)),
*/
- producePair(MaskWriteRegisterModbusAddress.of("maskwrite:1/1/2"), new MaskWriteRegisterResponse(1, 1, 2), dataTypePair.getValue()),
+ producePair(MaskWriteRegisterModbusAddress.of("maskwrite:1/1/2"), new MaskWriteRegisterResponse(1, 1, 2), mapDataTypePairForRegister(dataTypePair).getValue()),
producePair(dataTypePair.getDataTypeClass(), ReadDiscreteInputsModbusAddress.of("readdiscreteinputs:1"), new ReadDiscreteInputsResponse(Unpooled.wrappedBuffer(new byte[]{(byte) 0x01}))),
- producePair(dataTypePair.getDataTypeClass(), ReadHoldingRegistersModbusAddress.of("readholdingregisters:1"), new ReadHoldingRegistersResponse(Unpooled.wrappedBuffer(cutRegister(dataTypePair.getByteRepresentation())))),
- producePair(dataTypePair.getDataTypeClass(), ReadInputRegistersModbusAddress.of("readinputregisters:1"), new ReadInputRegistersResponse(Unpooled.wrappedBuffer(cutRegister(dataTypePair.getByteRepresentation())))),
- producePair(CoilModbusAddress.of("coil:1"), new WriteMultipleCoilsResponse(1, 3), dataTypePair.getValue(), dataTypePair.getValue(), dataTypePair.getValue()),
- producePair(RegisterModbusAddress.of("register:1"), new WriteMultipleRegistersResponse(1, 3), dataTypePair.getValue(), dataTypePair.getValue(), dataTypePair.getValue()),
- producePair(RegisterModbusAddress.of("register:1"), new WriteSingleRegisterResponse(1, cutRegister(dataTypePair.getByteRepresentation())[0]), dataTypePair.getValue())
+ producePair(dataTypePair.getDataTypeClass(), ReadHoldingRegistersModbusAddress.of("readholdingregisters:1"), new ReadHoldingRegistersResponse(Unpooled.wrappedBuffer(cutRegister(mapDataTypePairForRegister(dataTypePair).getByteRepresentation())))),
+ producePair(dataTypePair.getDataTypeClass(), ReadInputRegistersModbusAddress.of("readinputregisters:1"), new ReadInputRegistersResponse(Unpooled.wrappedBuffer(cutRegister(mapDataTypePairForRegister(dataTypePair).getByteRepresentation())))),
+ producePair(CoilModbusAddress.of("coil:1"), new WriteMultipleCoilsResponse(1, 3), mapDataTypePairForCoil(dataTypePair).getValue(), mapDataTypePairForCoil(dataTypePair).getValue(), mapDataTypePairForCoil(dataTypePair).getValue()),
+ producePair(RegisterModbusAddress.of("register:1"), new WriteMultipleRegistersResponse(1, 3), mapDataTypePairForRegister(dataTypePair).getValue(), mapDataTypePairForRegister(dataTypePair).getValue(), mapDataTypePairForRegister(dataTypePair).getValue()),
+ producePair(RegisterModbusAddress.of("register:1"), new WriteSingleRegisterResponse(1, cutRegister(mapDataTypePairForRegister(dataTypePair).getByteRepresentation())[0]), mapDataTypePairForRegister(dataTypePair).getValue())
))
.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());
@@ -165,7 +163,6 @@ public class Plc4XModbusProtocolTest {
private static byte[] cutRegister(byte[] right) {
return new byte[]{right.length > 1 ? right[right.length - 2] : 0x0, right[right.length - 1]};
}
-
@Before
public void setUp() {
SUT = new Plc4XModbusProtocol();
@@ -356,19 +353,19 @@ public class Plc4XModbusProtocolTest {
} else if (modbusPdu instanceof ReadCoilsResponse) {
ReadResponseItem readResponseItem = (ReadResponseItem) responseItem;
Object value = readResponseItem.getValues().get(0);
- defaultAssert(value);
+ defaultAssert(value, Plc4XModbusProtocolTest::mapDataTypePairForCoil);
} else if (modbusPdu instanceof ReadDiscreteInputsResponse) {
ReadResponseItem readResponseItem = (ReadResponseItem) responseItem;
Object value = readResponseItem.getValues().get(0);
- defaultAssert(value);
+ defaultAssert(value, Plc4XModbusProtocolTest::mapDataTypePairForCoil);
} else if (modbusPdu instanceof ReadHoldingRegistersResponse) {
ReadResponseItem readResponseItem = (ReadResponseItem) responseItem;
Object value = readResponseItem.getValues().get(0);
- defaultAssert(value);
+ defaultAssert(value, Plc4XModbusProtocolTest::mapDataTypePairForRegister);
} else if (modbusPdu instanceof ReadInputRegistersResponse) {
ReadResponseItem readResponseItem = (ReadResponseItem) responseItem;
Object value = readResponseItem.getValues().get(0);
- defaultAssert(value);
+ defaultAssert(value, Plc4XModbusProtocolTest::mapDataTypePairForRegister);
} else if (modbusPdu instanceof WriteMultipleCoilsResponse) {
WriteResponseItem writeResponseItem = (WriteResponseItem) responseItem;
assertEquals(ResponseCode.OK, writeResponseItem.getResponseCode());
@@ -384,6 +381,31 @@ public class Plc4XModbusProtocolTest {
}
}
+ private static Plc4XSupportedDataTypes.DataTypePair mapDataTypePairForCoil(Plc4XSupportedDataTypes.DataTypePair dataTypePair) {
+ return mapDataTypePairForRegisterOrCoil(dataTypePair, 1);
+ }
+
+ private static Plc4XSupportedDataTypes.DataTypePair mapDataTypePairForRegister(Plc4XSupportedDataTypes.DataTypePair dataTypePair) {
+ return mapDataTypePairForRegisterOrCoil(dataTypePair, 2);
+ }
+
+ private static Plc4XSupportedDataTypes.DataTypePair mapDataTypePairForRegisterOrCoil(Plc4XSupportedDataTypes.DataTypePair dataTypePair, int size) {
+ byte[] byteRepresentation = dataTypePair.getByteRepresentation();
+ if (dataTypePair.getDataTypeClass() == byte[].class) {
+ byte[] value = (byte[]) dataTypePair.getValue();
+ byte[] mappedValue = Arrays.copyOfRange(value, 0, size);
+ byte[] mappedByteRepresentation = Arrays.copyOfRange(byteRepresentation, 0, size);
+ return Plc4XSupportedDataTypes.DataTypePair.of(mappedValue, mappedByteRepresentation);
+ } else if (dataTypePair.getDataTypeClass() == Byte[].class) {
+ Byte[] value = (Byte[]) dataTypePair.getValue();
+ Byte[] mappedValue = Arrays.copyOfRange(value, 0, size);
+ byte[] mappedByteRepresentation = Arrays.copyOfRange(byteRepresentation, 0, size);
+ return Plc4XSupportedDataTypes.DataTypePair.of(mappedValue, mappedByteRepresentation);
+ } else {
+ return dataTypePair;
+ }
+ }
+
private void syncInvoiceId() throws Exception {
Field transactionId = SUT.getClass().getDeclaredField("transactionId");
transactionId.setAccessible(true);