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 14d558505a519cadfa7045a6b0b9e6b097362530
Author: Sebastian Rühl <sru...@apache.org>
AuthorDate: Thu Jul 26 11:13:58 2018 +0200

    added BigInteger support on modbus and ads
---
 .../ads/protocol/util/LittleEndianDecoder.java     | 12 ++++++
 .../ads/protocol/util/LittleEndianEncoder.java     | 18 ++++++++
 .../base/protocol/Plc4XSupportedDataTypes.java     | 14 ++++---
 .../java/modbus/netty/Plc4XModbusProtocol.java     | 48 ++++++++++++++++++++++
 .../java/modbus/netty/Plc4XModbusProtocolTest.java | 16 +++++++-
 5 files changed, 101 insertions(+), 7 deletions(-)

diff --git 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java
 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java
index 3539be0..dcea26f 100644
--- 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java
+++ 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java
@@ -18,6 +18,7 @@
  */
 package org.apache.plc4x.java.ads.protocol.util;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.plc4x.java.ads.api.commands.types.Length;
 import org.apache.plc4x.java.ads.api.commands.types.TimeStamp;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
@@ -97,6 +98,10 @@ public class LittleEndianDecoder {
             } else if (datatype == Integer.class) {
                 decodeInteger(safeLengthAdsData, i, result);
                 i += 4;
+            } else if (datatype == BigInteger.class) {
+                decodeBigInteger(safeLengthAdsData, result);
+                // A big integer can consume the whole stream
+                i = length;
             } else if (datatype == Float.class) {
                 decodeFloat(safeLengthAdsData, i, result);
                 i += 4;
@@ -143,6 +148,13 @@ public class LittleEndianDecoder {
         result.add((byteOne & 0xff) | ((byteTwo & 0xff) << 8) | ((byteThree & 
0xff) << 16) | (byteFour & 0xff) << 24);
     }
 
+    private static void decodeBigInteger(byte[] adsData, List<Object> result) {
+        byte[] clone = ArrayUtils.clone(adsData);
+        ArrayUtils.reverse(clone);
+        byte[] bigIntegerByteArray = ArrayUtils.insert(0, clone, (byte) 0x0);
+        result.add(new BigInteger(bigIntegerByteArray));
+    }
+
     private static void decodeFloat(byte[] adsData, int i, List<Object> 
result) {
         byte byteOne = adsData[i];
         byte byteTwo = adsData[i + 1];
diff --git 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java
 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java
index 5c75a61..6b147c5 100644
--- 
a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java
+++ 
b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java
@@ -39,6 +39,7 @@ public class LittleEndianEncoder {
         // Utility class
     }
 
+    // TODO: add bound checking
     public static byte[] encodeData(Class<?> valueType, Object... values) 
throws PlcProtocolException {
         if (values.length == 0) {
             return new byte[]{};
@@ -52,6 +53,8 @@ public class LittleEndianEncoder {
             result = encodeShort(Arrays.stream(values).map(Short.class::cast));
         } else if (valueType == Integer.class) {
             result = 
encodeInteger(Arrays.stream(values).map(Integer.class::cast));
+        } else if (valueType == BigInteger.class) {
+            result = 
encodeBigInteger(Arrays.stream(values).map(BigInteger.class::cast));
         } else if (valueType == Calendar.class || 
Calendar.class.isAssignableFrom(valueType)) {
             result = 
encodeCalendar(Arrays.stream(values).map(Calendar.class::cast));
         } else if (valueType == Float.class) {
@@ -128,6 +131,21 @@ public class LittleEndianEncoder {
             });
     }
 
+    private static Stream<byte[]> encodeBigInteger(Stream<BigInteger> 
bigIntegerStream) {
+        return bigIntegerStream
+            .map(bigIntValue -> {
+                byte[] bytes = bigIntValue.toByteArray();
+                if (bytes[0] == 0x0) {
+                    byte[] subArray = ArrayUtils.subarray(bytes, 1, 
bytes.length);
+                    ArrayUtils.reverse(subArray);
+                    return subArray;
+                } else {
+                    ArrayUtils.reverse(bytes);
+                    return bytes;
+                }
+            });
+    }
+
     private static Stream<byte[]> encodeCalendar(Stream<Calendar> 
calendarStream) {
         return calendarStream
             .map(Calendar.class::cast)
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 a8dc32c..f84e532 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
@@ -23,6 +23,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 
 import java.io.Serializable;
+import java.math.BigInteger;
 import java.util.*;
 import java.util.stream.Stream;
 
@@ -41,11 +42,12 @@ public class Plc4XSupportedDataTypes {
         littleEndianMap.put(Boolean.class, ImmutablePair.of(Boolean.TRUE, new 
byte[]{0x01}));
         littleEndianMap.put(Byte.class, ImmutablePair.of(Byte.valueOf("1"), 
new byte[]{0x1}));
         littleEndianMap.put(Short.class, ImmutablePair.of(Short.valueOf("1"), 
new byte[]{0x1, 0x0}));
-        littleEndianMap.put(Calendar.class, ImmutablePair.of(calenderInstance, 
new byte[]{0x0, (byte) 0x80, 0x3E, 0x15, (byte) 0xAB, 0x47, (byte) 0xFC, 
0x28}));
-        littleEndianMap.put(GregorianCalendar.class, 
littleEndianMap.get(Calendar.class));
         littleEndianMap.put(Float.class, ImmutablePair.of(Float.valueOf("1"), 
new byte[]{0x0, 0x0, (byte) 0x80, 0x3F}));
-        littleEndianMap.put(Double.class, 
ImmutablePair.of(Double.valueOf("1"), new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
(byte) 0xF0, 0x3F}));
         littleEndianMap.put(Integer.class, 
ImmutablePair.of(Integer.valueOf("1"), new byte[]{0x1, 0x0, 0x0, 0x0}));
+        littleEndianMap.put(Double.class, 
ImmutablePair.of(Double.valueOf("1"), new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
(byte) 0xF0, 0x3F}));
+        littleEndianMap.put(BigInteger.class, 
ImmutablePair.of(BigInteger.valueOf(1), new byte[]{0x1, 0x0, 0x0, 0x0}));
+        littleEndianMap.put(Calendar.class, ImmutablePair.of(calenderInstance, 
new byte[]{0x0, (byte) 0x80, 0x3E, 0x15, (byte) 0xAB, 0x47, (byte) 0xFC, 
0x28}));
+        littleEndianMap.put(GregorianCalendar.class, 
littleEndianMap.get(Calendar.class));
         littleEndianMap.put(String.class, 
ImmutablePair.of(String.valueOf("Hello World!"), new byte[]{0x48, 0x65, 0x6c, 
0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00}));
         bigEndianMap = new HashMap<>();
         littleEndianMap.forEach((clazz, pair) -> {
@@ -66,11 +68,13 @@ public class Plc4XSupportedDataTypes {
         return Stream.of(
             Boolean.class,
             Byte.class,
+            // TODO: add byte[]
             Short.class,
-            Calendar.class,
             Float.class,
-            Double.class,
             Integer.class,
+            Double.class,
+            BigInteger.class,
+            Calendar.class,
             String.class
         );
     }
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 9a050f4..b4914a8 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.math.BigInteger;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -260,6 +261,7 @@ public class Plc4XModbusProtocol extends 
MessageToMessageCodec<ModbusTcpPayload,
                     && !(value instanceof byte[])
                     && !(value instanceof Short)
                     && !(value instanceof Integer)
+                    && !(value instanceof BigInteger)
                 ) {
                 throw new PlcRuntimeException("Unsupported datatype detected " 
+ value.getClass());
             }
@@ -311,6 +313,8 @@ public class Plc4XModbusProtocol extends 
MessageToMessageCodec<ModbusTcpPayload,
                     throw new PlcProtocolException("Value to high to fit into 
Byte: " + value);
                 }
                 coilSet = (int) value == 1;
+            } else if (value.getClass() == BigInteger.class) {
+                coilSet = value.equals(BigInteger.ONE);
             }
             byte coilToSet = (coilSet ? (byte) 1 : (byte) 0);
             actualCoil = (byte) (actualCoil | coilToSet << i);
@@ -344,12 +348,41 @@ public class Plc4XModbusProtocol extends 
MessageToMessageCodec<ModbusTcpPayload,
                 }
                 buffer.writeBytes(bytes);
             } else if (value.getClass() == Short.class) {
+                if ((short) value < 0) {
+                    throw new PlcProtocolException("Only positive values are 
supported for Short: " + 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);
                 }
+                if ((int) value < 0) {
+                    throw new PlcProtocolException("Only positive values are 
supported for Integer: " + value);
+                }
                 buffer.writeShort((int) value);
+            } else if (value.getClass() == BigInteger.class) {
+                if (((BigInteger) value).compareTo(BigInteger.ZERO) < 0) {
+                    throw new PlcProtocolException("Only positive values are 
supported for BigInteger: " + value);
+                }
+                if (((BigInteger) 
value).compareTo(BigInteger.valueOf(0XFFFF_FFFFL)) > 0) {
+                    throw new PlcProtocolException("Value to high to fit into 
register: " + value);
+                }
+                // TODO: for now we can't support big values as we only write 
one register at once
+                if (((BigInteger) 
value).compareTo(BigInteger.valueOf(0XFFFFL)) > 0) {
+                    throw new PlcProtocolException("Value to high to fit into 
register: " + value);
+                }
+                // TODO: Register has 2 bytes so we trim to 2 instead of 4 
like the second if above
+                int maxBytes = 2;
+                byte[] bigIntegerBytes = ((BigInteger) value).toByteArray();
+                byte[] bytes = new byte[maxBytes];
+                int lengthToCopy = Math.min(bigIntegerBytes.length, maxBytes);
+                int srcPosition = Math.max(bigIntegerBytes.length - maxBytes, 
0);
+                int destPosition = maxBytes - lengthToCopy;
+                System.arraycopy(bigIntegerBytes, srcPosition, bytes, 
destPosition, lengthToCopy);
+
+                // TODO: check if this is a good representation.
+                // TODO: can a big integer span multiple registers?
+                buffer.writeBytes(bytes);
             }
         }
         byte[] result = new byte[buffer.writerIndex()];
@@ -393,6 +426,10 @@ public class Plc4XModbusProtocol extends 
MessageToMessageCodec<ModbusTcpPayload,
                 @SuppressWarnings("unchecked")
                 T itemToBeAdded = (T) Integer.valueOf(coilFlag);
                 data.add(itemToBeAdded);
+            } else if (dataType == BigInteger.class) {
+                @SuppressWarnings("unchecked")
+                T itemToBeAdded = (T) BigInteger.valueOf(coilFlag);
+                data.add(itemToBeAdded);
             }
         }
         return data;
@@ -431,9 +468,20 @@ public class Plc4XModbusProtocol extends 
MessageToMessageCodec<ModbusTcpPayload,
                 T itemToBeAdded = (T) Short.valueOf((short) intValue);
                 data.add(itemToBeAdded);
             } else if (dataType == Integer.class) {
+                if (intValue < 0) {
+                    throw new PlcProtocolException("Integer underflow: " + 
intValue);
+                }
                 @SuppressWarnings("unchecked")
                 T itemToBeAdded = (T) Integer.valueOf(intValue);
                 data.add(itemToBeAdded);
+            } else if (dataType == BigInteger.class) {
+                if (intValue < 0) {
+                    throw new PlcProtocolException("BigInteger underflow: " + 
intValue);
+                }
+                // TODO: can a big integer span multiple registers?
+                @SuppressWarnings("unchecked")
+                T itemToBeAdded = (T) new BigInteger(register);
+                data.add(itemToBeAdded);
             }
         }
         return data;
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 42b882e..f28cb69 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
@@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.math.BigInteger;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -167,7 +168,7 @@ public class Plc4XModbusProtocolTest {
                             .builder()
                             .addItem((Class) pair.getLeft().getClass(), 
RegisterModbusAddress.of("register:1"), pair.getLeft(), pair.getLeft(), 
pair.getLeft())
                             .build(), new CompletableFuture<>()),
-                    new ModbusTcpPayload((short) 0, (short) 0, new 
WriteMultipleCoilsResponse(1, 3))
+                    new ModbusTcpPayload((short) 0, (short) 0, new 
WriteMultipleRegistersResponse(1, 3))
                 ),
                 ImmutablePair.of(
                     new PlcRequestContainer<>(
@@ -175,7 +176,7 @@ public class Plc4XModbusProtocolTest {
                             .builder()
                             .addItem(RegisterModbusAddress.of("register:1"), 
pair.getLeft())
                             .build(), new CompletableFuture<>()),
-                    new ModbusTcpPayload((short) 0, (short) 0, new 
WriteSingleCoilResponse(1, pair.getRight()[0]))
+                    new ModbusTcpPayload((short) 0, (short) 0, new 
WriteSingleRegisterResponse(1, pair.getRight()[0]))
                 )
             ))
             .flatMap(stream -> stream)
@@ -228,6 +229,9 @@ public class Plc4XModbusProtocolTest {
             } else if (payloadClazzName.equals(Integer.class.getSimpleName())) 
{
                 assertThat(andMask, equalTo(1));
                 assertThat(orMask, equalTo(2));
+            } else if 
(payloadClazzName.equals(BigInteger.class.getSimpleName())) {
+                assertThat(andMask, equalTo(1));
+                assertThat(orMask, equalTo(2));
             } else if (payloadClazzName.equals(String.class.getSimpleName())) {
                 assertThat(andMask, equalTo(1));
                 assertThat(orMask, equalTo(2));
@@ -275,6 +279,8 @@ public class Plc4XModbusProtocolTest {
                 assertByteEquals(new byte[]{0x0}, bytes);
             } else if (payloadClazzName.equals(Integer.class.getSimpleName())) 
{
                 assertByteEquals(new byte[]{0x0}, bytes);
+            } else if 
(payloadClazzName.equals(BigInteger.class.getSimpleName())) {
+                assertByteEquals(new byte[]{0x0}, bytes);
             } else if (payloadClazzName.equals(String.class.getSimpleName())) {
                 assertByteEquals(new byte[]{0x0}, bytes);
             }
@@ -297,6 +303,8 @@ public class Plc4XModbusProtocolTest {
                 assertByteEquals(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
bytes);
             } else if (payloadClazzName.equals(Integer.class.getSimpleName())) 
{
                 assertByteEquals(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
bytes);
+            } else if 
(payloadClazzName.equals(BigInteger.class.getSimpleName())) {
+                assertByteEquals(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
bytes);
             } else if (payloadClazzName.equals(String.class.getSimpleName())) {
                 assertByteEquals(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
bytes);
             }
@@ -318,6 +326,8 @@ public class Plc4XModbusProtocolTest {
                 assertThat(coilValue, equalTo(true));
             } else if (payloadClazzName.equals(Integer.class.getSimpleName())) 
{
                 assertThat(coilValue, equalTo(true));
+            } else if 
(payloadClazzName.equals(BigInteger.class.getSimpleName())) {
+                assertThat(coilValue, equalTo(true));
             } else if (payloadClazzName.equals(String.class.getSimpleName())) {
                 assertThat(coilValue, equalTo(true));
             }
@@ -338,6 +348,8 @@ public class Plc4XModbusProtocolTest {
                 assertThat(value, equalTo(1));
             } else if (payloadClazzName.equals(Integer.class.getSimpleName())) 
{
                 assertThat(value, equalTo(1));
+            } else if 
(payloadClazzName.equals(BigInteger.class.getSimpleName())) {
+                assertThat(value, equalTo(1));
             } else if (payloadClazzName.equals(String.class.getSimpleName())) {
                 assertThat(value, equalTo(1));
             }

Reply via email to