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/11/01 11:19:38 UTC

[incubator-plc4x] branch master updated: [plc4j-ads] fixed encoder and decoder and enabled round-trip test

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 f452493  [plc4j-ads] fixed encoder and decoder and enabled round-trip test
f452493 is described below

commit f452493ca25dc43055434c765c5e0e1249cde29e
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Nov 1 12:19:22 2018 +0100

    [plc4j-ads] fixed encoder and decoder and enabled round-trip test
---
 .../apache/plc4x/java/ads/model/AdsDataType.java   | 72 ++++++++++++----------
 .../plc4x/java/ads/model/AdsPlcFieldHandler.java   | 65 ++++++-------------
 .../ads/protocol/util/LittleEndianDecoder.java     | 34 ++++------
 .../ads/protocol/util/LittleEndianEncoder.java     | 62 +++++++++++++------
 .../protocol/util/EncoderDecoderRoundTripTest.java | 56 ++++++++++++++---
 plc4j/protocols/ads/src/test/resources/logback.xml |  2 +-
 .../base/messages/items/BaseDefaultFieldItem.java  |  2 +-
 7 files changed, 162 insertions(+), 131 deletions(-)

diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java
index 771ccb7..6470803 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java
@@ -23,9 +23,11 @@ import org.apache.commons.lang3.ArrayUtils;
 import java.io.ByteArrayOutputStream;
 import java.math.BigInteger;
 import java.time.Duration;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.IntStream;
 
 /**
@@ -37,19 +39,19 @@ import java.util.stream.IntStream;
 public enum AdsDataType {
     // TODO: maybe this are just types for the plc ide and can be removed
     // https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=
-    BIT(8),
-    BIT8(8),
-    BITARR8(8),
-    BITARR16(16),
-    BITARR32(32),
-    INT8(8),
+    BIT(0, 1, 8),
+    BIT8((short) 0x00, (short) 0xFF, 8),
+    BITARR8((short) 0x00, (short) 0xFF, 8),
+    BITARR16(0x0000, 0xFFFF, 16),
+    BITARR32(0x0000_0000L, 0xFFFF_FFFFL, 32),
+    INT8(Byte.MIN_VALUE, Byte.MAX_VALUE, 8),
     INT16(Short.MIN_VALUE, Short.MAX_VALUE, 16),
     INT32(Integer.MIN_VALUE, Integer.MAX_VALUE, 32),
     INT64(Long.MIN_VALUE, Long.MAX_VALUE, 64),
-    UINT8(0, Short.MAX_VALUE, 8),
-    UINT16(0, Integer.MAX_VALUE, 16),
-    UINT32(0, produceUnsignedMaxValue(32), 32),
-    UINT64(0, produceUnsignedMaxValue(64), 64),
+    UINT8((short) 0, (short) 0xFF, 8),
+    UINT16(0, 0xFFFF, 16),
+    UINT32(0L, 0xFFFF_FFFFL, 32),
+    UINT64(BigInteger.ZERO, produceUnsignedMaxValue(8), 64),
     FLOAT(-Float.MAX_VALUE, Float.MAX_VALUE, 32),
     DOUBLE(-Double.MAX_VALUE, Double.MAX_VALUE, 64),
     // https://infosys.beckhoff.com/english.php?content=../content/1033/tcplccontrol/html/tcplcctrl_plc_data_types_overview.htm&id
@@ -67,7 +69,7 @@ public enum AdsDataType {
      * <p>
      * The boolean variable is in the same memory range as the byte variable.
      */
-    BOOL(8),
+    BOOL((byte) 0, (byte) 1, 8),
     /**
      * BYTE
      * <p>
@@ -76,7 +78,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * BYTE	0	255	8 Bit
      */
-    BYTE(0, 255, 8),
+    BYTE((short) 0, (short) 255, 8),
     /**
      * WORD
      * Integer data type.
@@ -92,7 +94,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * DWORD	0	4294967295	32 Bit
      */
-    DWORD(0, 4294967295L, 32),
+    DWORD(0L, 4294967295L, 32),
     /**
      * SINT
      * (Short) signed integer data type.
@@ -100,7 +102,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * SINT	-128	127	8 Bit
      */
-    SINT(-128, 127, 8),
+    SINT(Byte.MIN_VALUE, Byte.MAX_VALUE, 8),
     /**
      * USINT
      * Unsigned (short) integer data type.
@@ -108,7 +110,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * USINT	0	255	8 Bit
      */
-    USINT(0, 255, 8),
+    USINT((short) 0, (short) 0xFF, 8),
     /**
      * INT
      * Signed integer data type.
@@ -116,7 +118,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * INT	-32768	32767	16 Bit
      */
-    INT(-32768, 32767, 16),
+    INT(Short.MIN_VALUE, Short.MAX_VALUE, 16),
     /**
      * UINT
      * Unsigned integer data type.
@@ -140,15 +142,15 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * UDINT	0	4294967295	32 Bit
      */
-    UDINT(0, 4294967295L, 32),
+    UDINT(0L, 4294967295L, 32),
     /**
      * LINT  (64 bit integer, currently not supported by TwinCAT)
      */
-    LINT(64),
+    LINT(Long.MIN_VALUE, Long.MAX_VALUE, 64),
     /**
      * ULINT (Unsigned 64 bit integer, currently not supported by TwinCAT)
      */
-    ULINT(64),
+    ULINT(BigInteger.ZERO, produceUnsignedMaxValue(8), 64),
     /**
      * REAL
      * 32 Bit floating point data type. It is required to represent rational numbers.
@@ -185,7 +187,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * TIME	T#0ms	T#71582m47s295ms	32 Bit
      */
-    TIME(0, Duration.ofMinutes(71582).plusSeconds(47).plusMillis(295).toMillis(), 32),
+    TIME(0L, Duration.ofMinutes(71582).plusSeconds(47).plusMillis(295).toMillis(), 32),
     /**
      * TIME_OF_DAY
      * TOD
@@ -197,7 +199,7 @@ public enum AdsDataType {
      * <p>
      * TOD#00:00	TOD#1193:02:47.295	32 Bit
      *///TODO: strange maximum
-    TIME_OF_DAY(0, ChronoUnit.MILLIS.between(LocalTime.of(0, 0), LocalTime.of(23, 59, 59)), 32),
+    TIME_OF_DAY(0L, ChronoUnit.MILLIS.between(LocalTime.of(0, 0), LocalTime.of(23, 59, 59)), 32),
     /**
      * DATE
      * Date. The most significant digit is one second. The data type is handled internally like DWORD.
@@ -205,7 +207,7 @@ public enum AdsDataType {
      * Type	Lower bound	Upper bound	Memory use
      * DATE	D#1970-01-01	D#2106-02-06	32 Bit
      */
-    DATE(0, ChronoUnit.SECONDS.between(LocalDateTime.of(1970, 1, 1, 0, 0), LocalDateTime.of(2106, 2, 6, 0, 0)), 32),
+    DATE(0L, TimeUnit.DAYS.toSeconds(ChronoUnit.DAYS.between(LocalDate.of(1970, 1, 1), LocalDate.of(2106, 2, 6))), 32),
     /**
      * DATE_AND_TIME
      * DT
@@ -216,8 +218,8 @@ public enum AdsDataType {
      * DT
      * <p>
      * DT#1970-01-01-00:00	DT#2106-02-06-06:28:15	32 Bit
-     *////TODO: calculate max
-    DATE_AND_TIME(0, -1, 32),
+     */
+    DATE_AND_TIME(0L, ChronoUnit.SECONDS.between(LocalDateTime.of(1970, 1, 1, 0, 0), LocalDateTime.of(2106, 2, 6, 6, 28, 15)), 32),
     //User-defined Data Types
     /**
      * Arrays
@@ -495,9 +497,13 @@ public enum AdsDataType {
 
     private final String typeName;
 
-    private final double lowerBound;
+    private final Number lowerBound;
+
+    private final double lowerBoundDouble;
+
+    private final Number upperBound;
 
-    private final double upperBound;
+    private final double upperBoundDouble;
 
     private final int memoryUse;
 
@@ -508,9 +514,11 @@ public enum AdsDataType {
         this(0, Byte.MAX_VALUE, memoryUse);
     }
 
-    AdsDataType(double lowerBound, double upperBound, int memoryUse) {
+    AdsDataType(Number lowerBound, Number upperBound, int memoryUse) {
         this.lowerBound = lowerBound;
+        this.lowerBoundDouble = lowerBound.doubleValue();
         this.upperBound = upperBound;
+        this.upperBoundDouble = upperBound.doubleValue();
         this.typeName = name();
         this.memoryUse = memoryUse;
         this.targetByteSize = this.memoryUse / 8;
@@ -520,11 +528,11 @@ public enum AdsDataType {
         return typeName;
     }
 
-    public double getLowerBound() {
+    public Number getLowerBound() {
         return lowerBound;
     }
 
-    public double getUpperBound() {
+    public Number getUpperBound() {
         return upperBound;
     }
 
@@ -537,7 +545,7 @@ public enum AdsDataType {
     }
 
     public boolean withinBounds(double other) {
-        return other >= lowerBound && other <= upperBound;
+        return other >= lowerBoundDouble && other <= upperBoundDouble;
     }
 
     @Override
@@ -551,7 +559,7 @@ public enum AdsDataType {
             "} " + super.toString();
     }
 
-    private static double produceUnsignedMaxValue(int numberOfBytes) {
+    private static BigInteger produceUnsignedMaxValue(int numberOfBytes) {
         return new BigInteger(
             ArrayUtils.insert(
                 0,
@@ -564,6 +572,6 @@ public enum AdsDataType {
                     )
                     .toByteArray(),
                 (byte) 0x0)
-        ).doubleValue();
+        );
     }
 }
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java
index c6811e5..70d18df 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java
@@ -716,8 +716,6 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
 
     private BaseDefaultFieldItem internalEncodeInteger(PlcField field, Object[] values) {
         AdsField adsField = (AdsField) field;
-        BigDecimal minValue = BigDecimal.valueOf(adsField.getAdsDataType().getLowerBound());
-        BigDecimal maxValue = BigDecimal.valueOf(adsField.getAdsDataType().getUpperBound());
         Class<? extends BaseDefaultFieldItem> fieldType;
         switch (adsField.getAdsDataType()) {
             case BYTE:
@@ -772,16 +770,10 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                         "Value of type " + values[i].getClass().getName() +
                             " is not assignable to " + adsField.getAdsDataType().name() + " fields.");
                 }
-                BigDecimal value = BigDecimal.valueOf(((Number) values[i]).longValue());
-                if (minValue.compareTo(value) > 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + value.toString() + " exceeds allowed minimum for type "
-                            + adsField.getAdsDataType().name() + " (min " + minValue.toString() + ")");
-                }
-                if (maxValue.compareTo(value) < 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + value.toString() + " exceeds allowed maximum for type "
-                            + adsField.getAdsDataType().name() + " (max " + maxValue.toString() + ")");
+
+                Number value = (Number) values[i];
+                if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+                    throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
                 }
                 longValues[i] = value.longValue();
             }
@@ -800,15 +792,8 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                         "Value of type " + values[i].getClass().getName() +
                             " is not assignable to " + adsField.getAdsDataType().name() + " fields.");
                 }
-                if (minValue.compareTo(value) > 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + value.toString() + " exceeds allowed minimum for type "
-                            + adsField.getAdsDataType().name() + " (min " + minValue.toString() + ")");
-                }
-                if (maxValue.compareTo(value) < 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + value.toString() + " exceeds allowed maximum for type "
-                            + adsField.getAdsDataType().name() + " (max " + maxValue.toString() + ")");
+                if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+                    throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
                 }
                 bigIntegerValues[i] = value.toBigInteger();
             }
@@ -818,8 +803,6 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
 
     private BaseDefaultFieldItem internalEncodeFloatingPoint(PlcField field, Object[] values) {
         AdsField adsField = (AdsField) field;
-        BigDecimal minValue = BigDecimal.valueOf(adsField.getAdsDataType().getLowerBound());
-        BigDecimal maxValue = BigDecimal.valueOf(adsField.getAdsDataType().getUpperBound());
         Class<? extends BaseDefaultFieldItem> fieldType;
         switch (adsField.getAdsDataType()) {
             case REAL:
@@ -845,15 +828,9 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                             " is not assignable to " + adsField.getAdsDataType().name() + " fields.");
                 }
 
-                if (minValue.compareTo(new BigDecimal(floatingPointValues[i])) > 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + floatingPointValues[i] + " exceeds allowed minimum for type "
-                            + adsField.getAdsDataType().name() + " (min " + minValue.toString() + ")");
-                }
-                if (maxValue.compareTo(new BigDecimal(floatingPointValues[i])) < 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + floatingPointValues[i] + " exceeds allowed maximum for type "
-                            + adsField.getAdsDataType().name() + " (max " + maxValue.toString() + ")");
+                Number value = (Number) values[i];
+                if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+                    throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
                 }
             }
             return new DefaultDoubleFieldItem(floatingPointValues);
@@ -868,15 +845,9 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                             " is not assignable to " + adsField.getAdsDataType().name() + " fields.");
                 }
 
-                if (minValue.compareTo(new BigDecimal(floatingPointValues[i])) > 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + floatingPointValues[i] + " exceeds allowed minimum for type "
-                            + adsField.getAdsDataType().name() + " (min " + minValue.toString() + ")");
-                }
-                if (maxValue.compareTo(new BigDecimal(floatingPointValues[i])) < 0) {
-                    throw new IllegalArgumentException(
-                        "Value of " + floatingPointValues[i] + " exceeds allowed maximum for type "
-                            + adsField.getAdsDataType().name() + " (max " + maxValue.toString() + ")");
+                Number value = (Number) values[i];
+                if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+                    throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
                 }
             }
             return new DefaultFloatFieldItem(floatingPointValues);
@@ -885,7 +856,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
 
     private BaseDefaultFieldItem internalEncodeString(PlcField field, Object[] values) {
         AdsField adsField = (AdsField) field;
-        double maxLength = adsField.getAdsDataType().getUpperBound();
+        Number maxLength = adsField.getAdsDataType().getUpperBound();
         //boolean encoding16Bit;
         switch (adsField.getAdsDataType()) {
             case STRING:
@@ -899,7 +870,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
         for (Object value : values) {
             if (value instanceof String) {
                 String stringValue = (String) value;
-                if (stringValue.length() > maxLength) {
+                if (stringValue.length() > maxLength.intValue()) {
                     throw new IllegalArgumentException(
                         "String length " + stringValue.length() + " exceeds allowed maximum for type "
                             + adsField.getAdsDataType().name() + " (max " + maxLength + ")");
@@ -913,7 +884,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                 /*if (encoding16Bit) {
                     stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
                 } else {*/
-                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
                 /*}*/
             } else if (value instanceof Short) {
                 Short shortValue = (Short) value;
@@ -923,7 +894,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                 /*if (encoding16Bit) {
                     stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
                 } else {*/
-                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
                 /*}*/
             } else if (value instanceof Integer) {
                 Integer integerValue = (Integer) value;
@@ -935,7 +906,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                 /*if (encoding16Bit) {
                     stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
                 } else {*/
-                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
                 /*}*/
             } else if (value instanceof Long) {
                 Long longValue = (Long) value;
@@ -951,7 +922,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler {
                 /*if (encoding16Bit) {
                     stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
                 } else {*/
-                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
                 /*}*/
             } else {
                 throw new IllegalArgumentException(
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 950e4b4..4bd92d3 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
@@ -104,19 +104,16 @@ public class LittleEndianDecoder {
             case INT32: {
                 LinkedList<Integer> values = new LinkedList<>();
                 while (wrappedBuffer.isReadable()) {
-                    int aLong = wrappedBuffer.readIntLE();
-                    values.offer(aLong);
+                    int intLE = wrappedBuffer.readIntLE();
+                    values.offer(intLE);
                 }
                 return new DefaultIntegerFieldItem(values.toArray(new Integer[0]));
             }
             case INT64: {
                 LinkedList<Long> values = new LinkedList<>();
                 while (wrappedBuffer.isReadable()) {
-                    byte[] bytes = new byte[8];
-                    wrappedBuffer.readBytes(bytes);
-                    BigInteger bigInteger = new BigInteger(bytes);
-                    // TODO: potential dataloss here.
-                    values.offer(bigInteger.longValue());
+                    long longLE = wrappedBuffer.readLongLE();
+                    values.offer(longLE);
                 }
                 return new DefaultLongFieldItem(values.toArray(new Long[0]));
             }
@@ -144,16 +141,17 @@ public class LittleEndianDecoder {
                 }
                 return new DefaultLongFieldItem(values.toArray(new Long[0]));
             }
+            case ULINT:
             case UINT64: {
-                LinkedList<Long> values = new LinkedList<>();
+                LinkedList<BigInteger> values = new LinkedList<>();
                 while (wrappedBuffer.isReadable()) {
-                    byte[] bytes = new byte[64];
+                    byte[] bytes = new byte[8];
                     wrappedBuffer.readBytes(bytes);
-                    BigInteger bigInteger = new BigInteger(ArrayUtils.add(bytes, (byte) 0x0));
-                    // TODO: potential dataloss here.
-                    values.offer(bigInteger.longValue());
+                    ArrayUtils.reverse(bytes);
+                    BigInteger bigInteger = new BigInteger(ArrayUtils.insert(0, bytes, (byte) 0x0));
+                    values.offer(bigInteger);
                 }
-                return new DefaultLongFieldItem(values.toArray(new Long[0]));
+                return new DefaultBigIntegerFieldItem(values.toArray(new BigInteger[0]));
             }
             case FLOAT: {
                 LinkedList<Float> values = new LinkedList<>();
@@ -259,16 +257,6 @@ public class LittleEndianDecoder {
                 }
                 return new DefaultLongFieldItem(values.toArray(new Long[0]));
             }
-            case ULINT: {
-                LinkedList<BigInteger> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    byte[] bytes = new byte[64];
-                    wrappedBuffer.readBytes(bytes);
-                    BigInteger bigInteger = new BigInteger(ArrayUtils.add(bytes, (byte) 0x0));
-                    values.offer(bigInteger);
-                }
-                return new DefaultBigIntegerFieldItem(values.toArray(new BigInteger[0]));
-            }
             case REAL: {
                 LinkedList<Float> values = new LinkedList<>();
                 while (wrappedBuffer.isReadable()) {
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 de41485..272d451 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
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.ads.protocol.util;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.plc4x.java.ads.model.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
+import org.apache.plc4x.java.api.exceptions.PlcProtocolPayloadTooBigException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
 
@@ -102,17 +103,28 @@ public class LittleEndianEncoder {
         return stringStream
             .map(s -> s.getBytes(Charset.defaultCharset()))
             // TODO: this 0 termination is from s7 but might be completly wrong in ads. Guess its a terminator
-            .map(bytes -> ArrayUtils.add(bytes, (byte) 0x0));
+            .map(bytes -> ArrayUtils.add(bytes, (byte) 0x0))
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeByteArray(AdsDataType adsDataType, Stream<byte[]> byteArrayStream) {
         // TODO: add boundchecks and add optional extension
-        return byteArrayStream;
+        return byteArrayStream
+            .peek(bytes -> {
+                if (bytes.length > adsDataType.getTargetByteSize()) {
+                    throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getTargetByteSize(), bytes.length, bytes));
+                }
+            });
     }
 
     private static Stream<byte[]> encodeBigByteArray(AdsDataType adsDataType, Stream<Byte[]> byteArrayStream) {
         // TODO: add boundchecks and add optional extension
-        return byteArrayStream.map(ArrayUtils::toPrimitive);
+        return byteArrayStream.map(ArrayUtils::toPrimitive)
+            .peek(bytes -> {
+                if (bytes.length > adsDataType.getTargetByteSize()) {
+                    throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getTargetByteSize(), bytes.length, bytes));
+                }
+            });
     }
 
     private static Stream<byte[]> encodeFloat(AdsDataType adsDataType, Stream<Float> floatStream) {
@@ -125,7 +137,8 @@ public class LittleEndianEncoder {
                 (byte) ((intValue & 0x0000ff00) >> 8),
                 (byte) ((intValue & 0x00ff0000) >> 16),
                 (byte) ((intValue & 0xff000000) >> 24),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeDouble(AdsDataType adsDataType, Stream<Double> doubleStream) {
@@ -142,7 +155,8 @@ public class LittleEndianEncoder {
                 (byte) ((longValue & 0x0000ff00_00000000L) >> 40),
                 (byte) ((longValue & 0x00ff0000_00000000L) >> 48),
                 (byte) ((longValue & 0xff000000_00000000L) >> 56),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeInteger(AdsDataType adsDataType, Stream<Integer> integerStream) {
@@ -153,11 +167,12 @@ public class LittleEndianEncoder {
                 (byte) ((intValue & 0x0000ff00) >> 8),
                 (byte) ((intValue & 0x00ff0000) >> 16),
                 (byte) ((intValue & 0xff000000) >> 24),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
-    private static Stream<byte[]> encodeLong(AdsDataType adsDataType, Stream<Long> integerStream) {
-        return integerStream
+    private static Stream<byte[]> encodeLong(AdsDataType adsDataType, Stream<Long> longStream) {
+        return longStream
             .peek(value -> checkBound(adsDataType, value))
             .map(longValue -> new byte[]{
                 (byte) (longValue & 0x00000000_000000ffL),
@@ -168,7 +183,8 @@ public class LittleEndianEncoder {
                 (byte) ((longValue & 0x0000ff00_00000000L) >> 40),
                 (byte) ((longValue & 0x00ff0000_00000000L) >> 48),
                 (byte) ((longValue & 0xff000000_00000000L) >> 56),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeBigInteger(AdsDataType adsDataType, Stream<BigInteger> bigIntegerStream) {
@@ -176,15 +192,16 @@ public class LittleEndianEncoder {
         return bigIntegerStream
             .map(bigIntValue -> {
                 byte[] bytes = bigIntValue.toByteArray();
-                if (bytes[0] == 0x0) {
-                    byte[] subArray = ArrayUtils.subarray(bytes, 1, bytes.length);
+                if (bytes.length > 1 && bytes[0] == 0x0) {
+                    byte[] subArray = Arrays.copyOf(ArrayUtils.subarray(bytes, 1, bytes.length), adsDataType.getTargetByteSize());
                     ArrayUtils.reverse(subArray);
                     return subArray;
                 } else {
-                    ArrayUtils.reverse(bytes);
+                    ArrayUtils.reverse(Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
                     return bytes;
                 }
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeLocalTime(AdsDataType adsDataType, Stream<LocalTime> localTimeStream) {
@@ -197,7 +214,8 @@ public class LittleEndianEncoder {
                 (byte) ((time & 0x00000000_0000ff00L) >> 8),
                 (byte) ((time & 0x00000000_00ff0000L) >> 16),
                 (byte) ((time & 0x00000000_ff000000L) >> 24),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeLocalDate(AdsDataType adsDataType, Stream<LocalDate> localDateStream) {
@@ -212,7 +230,8 @@ public class LittleEndianEncoder {
                 (byte) ((time & 0x00000000_0000ff00L) >> 8),
                 (byte) ((time & 0x00000000_00ff0000L) >> 16),
                 (byte) ((time & 0x00000000_ff000000L) >> 24),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeLocalDateTime(AdsDataType adsDataType, Stream<LocalDateTime> localDateTimeStream) {
@@ -231,7 +250,8 @@ public class LittleEndianEncoder {
                 (byte) ((time & 0x0000ff00_00000000L) >> 40),
                 (byte) ((time & 0x00ff0000_00000000L) >> 48),
                 (byte) ((time & 0xff000000_00000000L) >> 56),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
 
@@ -241,19 +261,21 @@ public class LittleEndianEncoder {
             .map(shortValue -> new byte[]{
                 (byte) (shortValue & 0x00ff),
                 (byte) ((shortValue & 0xff00) >> 8),
-            });
+            })
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeByte(AdsDataType adsDataType, Stream<Byte> byteStream) {
         return byteStream
             .peek(value -> checkBound(adsDataType, value))
-            .map(aByte -> new byte[]{aByte});
+            .map(aByte -> new byte[]{aByte})
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static Stream<byte[]> encodeBoolean(AdsDataType adsDataType, Stream<Boolean> booleanStream) {
-        // TODO: add boundchecks and add optional extension
         return booleanStream
-            .map(booleanValue -> new byte[]{booleanValue ? (byte) 0x01 : (byte) 0x00});
+            .map(booleanValue -> new byte[]{booleanValue ? (byte) 0x01 : (byte) 0x00})
+            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
     }
 
     private static void checkBound(AdsDataType adsDataType, double other) {
diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/EncoderDecoderRoundTripTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/EncoderDecoderRoundTripTest.java
index a7f693f..f0c38aa 100644
--- a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/EncoderDecoderRoundTripTest.java
+++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/util/EncoderDecoderRoundTripTest.java
@@ -20,39 +20,81 @@
 package org.apache.plc4x.java.ads.protocol.util;
 
 import org.apache.plc4x.java.ads.model.AdsDataType;
-import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
+import org.apache.plc4x.java.base.messages.items.*;
+import org.apache.plc4x.java.base.util.HexUtil;
 import org.assertj.core.api.WithAssertions;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
 import java.util.Arrays;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-@Disabled("check if the encoder/decoder can be used like this.")
 public class EncoderDecoderRoundTripTest implements WithAssertions {
 
+    private static Set<AdsDataType> untestedDataTypes = Stream.of(
+        AdsDataType.STRING,
+        AdsDataType.ARRAY,
+        AdsDataType.POINTER,
+        AdsDataType.ENUM,
+        AdsDataType.STRUCT,
+        AdsDataType.ALIAS,
+        AdsDataType.SUB_RANGE_DATA_TYPE,
+        AdsDataType.UNKNOWN
+    ).collect(Collectors.toSet());
+
     @ParameterizedTest
     @MethodSource("generateData")
-    public void testMin(AdsDataType adsDataType, Double min, Double max) throws Exception {
+    public void testMin(AdsDataType adsDataType, Number min, Number unused) throws Exception {
         byte[] bytes = LittleEndianEncoder.encodeData(adsDataType, min);
+        assertThat(bytes).isNotEmpty();
+        assertThat(bytes).hasSize(adsDataType.getTargetByteSize());
         BaseDefaultFieldItem baseDefaultFieldItem = LittleEndianDecoder.decodeData(adsDataType, bytes);
 
-        assertThat(baseDefaultFieldItem.getDouble(0)).isEqualTo(min);
+        if (baseDefaultFieldItem instanceof DefaultBooleanFieldItem) {
+            assertThat(baseDefaultFieldItem.getBoolean(0)).isEqualTo(false);
+        } else if (baseDefaultFieldItem instanceof DefaultLocalTimeFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalTime.ofNanoOfDay(TimeUnit.MILLISECONDS.toNanos((Long) min)));
+        } else if (baseDefaultFieldItem instanceof DefaultLocalDateFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalDate.ofEpochDay(TimeUnit.SECONDS.toDays((Long) min)));
+        } else if (baseDefaultFieldItem instanceof DefaultLocalDateTimeFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalDateTime.ofEpochSecond((Long) min, 0, ZoneOffset.UTC));
+        } else {
+            assertThat(baseDefaultFieldItem.getObject(0)).as("Min of %s using %s is equals %s\n%s", baseDefaultFieldItem, adsDataType, min, HexUtil.toHex(bytes)).isEqualTo(min);
+        }
     }
 
     @ParameterizedTest
     @MethodSource("generateData")
-    public void testMax(AdsDataType adsDataType, Double min, Double max) throws Exception {
+    public void testMax(AdsDataType adsDataType, Number unused, Number max) throws Exception {
         byte[] bytes = LittleEndianEncoder.encodeData(adsDataType, max);
+        assertThat(bytes).isNotEmpty();
+        assertThat(bytes).hasSize(adsDataType.getTargetByteSize());
         BaseDefaultFieldItem baseDefaultFieldItem = LittleEndianDecoder.decodeData(adsDataType, bytes);
 
-        assertThat(baseDefaultFieldItem.getDouble(0)).isEqualTo(max);
+        if (baseDefaultFieldItem instanceof DefaultBooleanFieldItem) {
+            assertThat(baseDefaultFieldItem.getBoolean(0)).isEqualTo(true);
+        } else if (baseDefaultFieldItem instanceof DefaultLocalTimeFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalTime.ofNanoOfDay(TimeUnit.MILLISECONDS.toNanos((Long) max)));
+        } else if (baseDefaultFieldItem instanceof DefaultLocalDateFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalDate.ofEpochDay(TimeUnit.SECONDS.toDays((Long) max)));
+        } else if (baseDefaultFieldItem instanceof DefaultLocalDateTimeFieldItem) {
+            assertThat(baseDefaultFieldItem.getObject(0)).isEqualTo(LocalDateTime.ofEpochSecond((Long) max, 0, ZoneOffset.UTC));
+        } else {
+            assertThat(baseDefaultFieldItem.getObject(0)).as("Max of %s using %s is equals %s\n%s", baseDefaultFieldItem, adsDataType, max, HexUtil.toHex(bytes)).isEqualTo(max);
+        }
     }
 
     public static Stream<Arguments> generateData() {
         return Arrays.stream(AdsDataType.values())
+            .filter(adsDataType -> !untestedDataTypes.contains(adsDataType))
             .map(adsDataType -> Arguments.of(adsDataType, adsDataType.getLowerBound(), adsDataType.getUpperBound()));
     }
 }
diff --git a/plc4j/protocols/ads/src/test/resources/logback.xml b/plc4j/protocols/ads/src/test/resources/logback.xml
index 5bfdbdc..dd243bd 100644
--- a/plc4j/protocols/ads/src/test/resources/logback.xml
+++ b/plc4j/protocols/ads/src/test/resources/logback.xml
@@ -31,7 +31,7 @@
     </encoder>
   </appender>
 
-  <root level="debug">
+  <root level="info">
     <appender-ref ref="STDOUT" />
   </root>
 
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java
index e41b2e5..0574a10 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java
@@ -183,7 +183,7 @@ public abstract class BaseDefaultFieldItem<T> {
 
     @Override
     public String toString() {
-        return "FieldItem{" +
+        return getClass().getSimpleName() + "{" +
             "values=" + Arrays.toString(values) +
             '}';
     }