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