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/09/06 14:06:32 UTC

[incubator-plc4x] branch feature/api-redesign-chris-c updated: some (little) progress on ADS api refactoring

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch feature/api-redesign-chris-c
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/feature/api-redesign-chris-c by this push:
     new 88a3df1  some (little) progress on ADS api refactoring
88a3df1 is described below

commit 88a3df1ab15d4d5e14162dce9f1e685a0aaef17d
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Sep 6 16:06:28 2018 +0200

    some (little) progress on ADS api refactoring
---
 .../java/api/connection/PlcProprietarySender.java  |   2 +-
 .../java/api/messages/PlcProprietaryResponse.java  |   2 +-
 .../java/api/messages/PlcSubscriptionRequest.java  |  12 +-
 .../ads/connection/AdsAbstractPlcConnection.java   |  29 ++---
 .../java/ads/connection/AdsTcpPlcConnection.java   |  39 +++---
 .../apache/plc4x/java/ads/model/AdsDataType.java   |  61 ++++++---
 .../org/apache/plc4x/java/ads/model/AdsField.java  |   7 +-
 .../plc4x/java/ads/model/SymbolicAdsField.java     |  29 ++++-
 .../plc4x/java/ads/protocol/Plc4x2AdsProtocol.java |  92 ++++++++------
 .../ads/protocol/util/LittleEndianDecoder.java     | 139 ++++++++++++++++++++-
 .../ads/protocol/util/LittleEndianEncoder.java     |  59 +++++----
 .../messages/DefaultPlcProprietaryRequest.java     |   4 +-
 .../messages/DefaultPlcProprietaryResponse.java    |  11 +-
 .../messages/DefaultPlcSubscriptionRequest.java    |  26 +++-
 .../java/base/messages/DefaultPlcWriteRequest.java |   7 +-
 ...est.java => InternalPlcProprietaryRequest.java} |   5 +-
 ...st.java => InternalPlcProprietaryResponse.java} |   7 +-
 .../base/messages/InternalPlcWriteRequest.java     |   6 +
 .../plc4x/java/base/messages/items/FieldItem.java  |   2 +-
 19 files changed, 387 insertions(+), 152 deletions(-)

diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcProprietarySender.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcProprietarySender.java
index efcdc3f..f735449 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcProprietarySender.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcProprietarySender.java
@@ -25,5 +25,5 @@ import java.util.concurrent.CompletableFuture;
 
 public interface PlcProprietarySender {
 
-    <PROP_REQUEST, PROP_RESPONSE> CompletableFuture<PlcProprietaryResponse<PROP_REQUEST, PROP_RESPONSE>> send(PlcProprietaryRequest<PROP_REQUEST> proprietaryRequest);
+    <PROP_REQUEST, PROP_RESPONSE> CompletableFuture<? extends PlcProprietaryResponse<? extends PlcProprietaryRequest<PROP_REQUEST>, PROP_RESPONSE>> send(PlcProprietaryRequest<PROP_REQUEST> proprietaryRequest);
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcProprietaryResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcProprietaryResponse.java
index 23ff22f..2e3bf58 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcProprietaryResponse.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcProprietaryResponse.java
@@ -18,6 +18,6 @@
  */
 package org.apache.plc4x.java.api.messages;
 
-public interface PlcProprietaryResponse<REQUEST, RESPONSE> extends PlcResponse<PlcProprietaryRequest<REQUEST>> {
+public interface PlcProprietaryResponse<REQUEST extends PlcProprietaryRequest, RESPONSE> extends PlcResponse<REQUEST> {
     RESPONSE getResponse();
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
index fc95e00..f88137f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
@@ -22,14 +22,14 @@ import java.time.Duration;
 
 public interface PlcSubscriptionRequest extends PlcFieldRequest {
 
-    PlcMessageBuilder<PlcSubscriptionRequest> builder();
+    PlcSubscriptionRequest.Builder builder();
 
     interface Builder extends PlcMessageBuilder<PlcSubscriptionRequest> {
         /**
          * Adds a new field to the to be constructed request which should be polled cyclically.
          *
-         * @param name alias of the field.
-         * @param fieldQuery field query string for accessing the field.
+         * @param name            alias of the field.
+         * @param fieldQuery      field query string for accessing the field.
          * @param pollingInterval interval, in which the field should be polled.
          * @return
          */
@@ -39,7 +39,7 @@ public interface PlcSubscriptionRequest extends PlcFieldRequest {
          * Adds a new field to the to be constructed request which should be updated as soon as
          * a value changes in the PLC.
          *
-         * @param name alias of the field.
+         * @param name       alias of the field.
          * @param fieldQuery field query string for accessing the field.
          * @return
          */
@@ -48,10 +48,10 @@ public interface PlcSubscriptionRequest extends PlcFieldRequest {
         /**
          * Adds a new subscription to the to be constructed request which should be updated
          * as soon as an event occurs.
-         *
+         * <p>
          * REMARK: We will have to see if this signature is correct as soon as we start using this type of subscription.
          *
-         * @param name alias of the field.
+         * @param name       alias of the field.
          * @param fieldQuery field query string for accessing the field.
          * @return
          */
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
index 79eb938..f9e0917 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsAbstractPlcConnection.java
@@ -39,10 +39,7 @@ import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.base.connection.AbstractPlcConnection;
 import org.apache.plc4x.java.base.connection.ChannelFactory;
-import org.apache.plc4x.java.base.messages.DefaultPlcProprietaryRequest;
-import org.apache.plc4x.java.base.messages.DefaultPlcReadRequest;
-import org.apache.plc4x.java.base.messages.DefaultPlcWriteRequest;
-import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,10 +92,10 @@ public abstract class AdsAbstractPlcConnection extends AbstractPlcConnection imp
     }
 
     @Override
-    public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+    public CompletableFuture<InternalPlcReadResponse> read(PlcReadRequest readRequest) {
         mapFields(readRequest);
-        CompletableFuture<PlcReadResponse> readFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>(readRequest, readFuture));
+        CompletableFuture<InternalPlcReadResponse> readFuture = new CompletableFuture<>();
+        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcReadRequest) readRequest, readFuture));
         channelFuture.addListener(future -> {
             if (!future.isSuccess()) {
                 readFuture.completeExceptionally(future.cause());
@@ -113,10 +110,10 @@ public abstract class AdsAbstractPlcConnection extends AbstractPlcConnection imp
     }
 
     @Override
-    public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
+    public CompletableFuture<InternalPlcWriteResponse> write(PlcWriteRequest writeRequest) {
         mapFields(writeRequest);
-        CompletableFuture<PlcWriteResponse> writeFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>(writeRequest, writeFuture));
+        CompletableFuture<InternalPlcWriteResponse> writeFuture = new CompletableFuture<>();
+        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcWriteRequest) writeRequest, writeFuture));
         channelFuture.addListener(future -> {
             if (!future.isSuccess()) {
                 writeFuture.completeExceptionally(future.cause());
@@ -131,9 +128,9 @@ public abstract class AdsAbstractPlcConnection extends AbstractPlcConnection imp
     }
 
     @Override
-    public <REQUEST, RESPONSE> CompletableFuture<PlcProprietaryResponse<REQUEST, RESPONSE>> send(PlcProprietaryRequest<REQUEST> proprietaryRequest) {
-        CompletableFuture<PlcProprietaryResponse<REQUEST, RESPONSE>> sendFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>(proprietaryRequest, sendFuture));
+    public <PROP_REQUEST, PROP_RESPONSE> CompletableFuture<? extends PlcProprietaryResponse<? extends PlcProprietaryRequest<PROP_REQUEST>, PROP_RESPONSE>> send(PlcProprietaryRequest<PROP_REQUEST> proprietaryRequest) {
+        CompletableFuture<InternalPlcProprietaryResponse<PROP_REQUEST, PROP_RESPONSE>> sendFuture = new CompletableFuture<>();
+        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcProprietaryRequest<PROP_REQUEST>) proprietaryRequest, sendFuture));
         channelFuture.addListener(future -> {
             if (!future.isSuccess()) {
                 sendFuture.completeExceptionally(future.cause());
@@ -168,9 +165,9 @@ public abstract class AdsAbstractPlcConnection extends AbstractPlcConnection imp
             );
 
             // TODO: This is blocking, should be changed to be async.
-            CompletableFuture<PlcProprietaryResponse<AdsReadWriteRequest, AdsReadWriteResponse>> getHandelFuture = new CompletableFuture<>();
+            CompletableFuture<InternalPlcProprietaryResponse<InternalPlcProprietaryRequest<AdsWriteRequest>, AdsReadWriteResponse>> getHandelFuture = new CompletableFuture<>();
             channel.writeAndFlush(new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsReadWriteRequest), getHandelFuture));
-            PlcProprietaryResponse<AdsReadWriteRequest, AdsReadWriteResponse> getHandleResponse = getFromFuture(getHandelFuture, SYMBOL_RESOLVE_TIMEOUT);
+            InternalPlcProprietaryResponse<InternalPlcProprietaryRequest<AdsWriteRequest>, AdsReadWriteResponse> getHandleResponse = getFromFuture(getHandelFuture, SYMBOL_RESOLVE_TIMEOUT);
             AdsReadWriteResponse response = getHandleResponse.getResponse();
 
             if (response.getResult().toAdsReturnCode() != AdsReturnCode.ADS_CODE_0) {
@@ -178,7 +175,7 @@ public abstract class AdsAbstractPlcConnection extends AbstractPlcConnection imp
             }
 
             IndexOffset symbolHandle = IndexOffset.of(response.getData().getBytes());
-            return AdsField.of(IndexGroup.ReservedGroups.ADSIGRP_SYM_VALBYHND.getAsLong(), symbolHandle.getAsLong());
+            return AdsField.of(IndexGroup.ReservedGroups.ADSIGRP_SYM_VALBYHND.getAsLong(), symbolHandle.getAsLong(), symbolicAdsFieldInternal.getAdsDataType(), symbolicAdsFieldInternal.getNumberOfElements());
         });
     }
 
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsTcpPlcConnection.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsTcpPlcConnection.java
index efe2f5f..687f7b0 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsTcpPlcConnection.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsTcpPlcConnection.java
@@ -27,6 +27,7 @@ import org.apache.plc4x.java.ads.api.commands.types.*;
 import org.apache.plc4x.java.ads.api.generic.types.AmsNetId;
 import org.apache.plc4x.java.ads.api.generic.types.AmsPort;
 import org.apache.plc4x.java.ads.api.generic.types.Invoke;
+import org.apache.plc4x.java.ads.model.AdsDataType;
 import org.apache.plc4x.java.ads.model.AdsField;
 import org.apache.plc4x.java.ads.model.AdsSubscriptionHandle;
 import org.apache.plc4x.java.ads.model.SymbolicAdsField;
@@ -39,14 +40,10 @@ import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
-import org.apache.plc4x.java.api.messages.items.SubscriptionEventItem;
-import org.apache.plc4x.java.api.messages.items.SubscriptionRequestItem;
-import org.apache.plc4x.java.api.messages.items.SubscriptionResponseItem;
-import org.apache.plc4x.java.api.messages.items.UnsubscriptionRequestItem;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.base.connection.TcpSocketChannelFactory;
-import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,6 +58,9 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 
+import static org.apache.plc4x.java.api.types.PlcSubscriptionType.CHANGE_OF_STATE;
+import static org.apache.plc4x.java.api.types.PlcSubscriptionType.CYCLIC;
+
 public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements PlcSubscriber {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AdsTcpPlcConnection.class);
@@ -142,18 +142,12 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
             throw new PlcNotImplementedException("Multirequest on subscribe not implemented yet");
         }
 
-        PlcField plcField = subscriptionRequest.getFields().get(0);
-        SubscriptionRequestItem<?> subscriptionRequestItem = subscriptionRequest.getRequestItem().orElseThrow(NullPointerException::new);
-
-        Objects.requireNonNull(subscriptionRequestItem.getConsumer());
-        Objects.requireNonNull(subscriptionRequestItem.getField());
-        Objects.requireNonNull(subscriptionRequestItem.getDatatype());
-
-        PlcField field = subscriptionRequestItem.getField();
-        Class<?> datatype = subscriptionRequestItem.getDatatype();
+        PlcField field = subscriptionRequest.getFields().get(0);
 
         IndexGroup indexGroup;
         IndexOffset indexOffset;
+        AdsDataType adsDataType;
+        int numberOfElements;
         // If this is a symbolic field, it has to be resolved first.
         // TODO: This is blocking, should be changed to be async.
         if (field instanceof SymbolicAdsField) {
@@ -164,6 +158,8 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
             }
             indexGroup = IndexGroup.of(adsField.getIndexGroup());
             indexOffset = IndexOffset.of(adsField.getIndexOffset());
+            adsDataType = adsField.getAdsDataType();
+            numberOfElements = adsField.getNumberOfElements();
         }
         // If it's no symbolic field, we can continue immediately
         // without having to do any resolving.
@@ -171,6 +167,8 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
             AdsField adsField = (AdsField) field;
             indexGroup = IndexGroup.of(adsField.getIndexGroup());
             indexOffset = IndexOffset.of(adsField.getIndexOffset());
+            adsDataType = adsField.getAdsDataType();
+            numberOfElements = adsField.getNumberOfElements();
         } else {
             throw new IllegalArgumentException("Unsupported field type " + field.getClass());
         }
@@ -196,8 +194,7 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
             Invoke.NONE,
             indexGroup,
             indexOffset,
-            // TODO: length determination doesn't work here really as this is only known within the plc or by the developer
-            Length.of(LittleEndianDecoder.getLengthFor(datatype, 1)),
+            Length.of(adsDataType.getTagetByteSize() * numberOfElements),
             transmissionMode,
             MaxDelay.of(0),
             CycleTime.of(4000000)
@@ -205,9 +202,9 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
 
         // Send the request to the plc and wait for a response
         // TODO: This is blocking, should be changed to be async.
-        CompletableFuture<PlcProprietaryResponse<AdsAddDeviceNotificationResponse>> addDeviceFuture = new CompletableFuture<>();
-        channel.writeAndFlush(new PlcRequestContainer<>(new PlcProprietaryRequest<>(adsAddDeviceNotificationRequest), addDeviceFuture));
-        PlcProprietaryResponse<AdsAddDeviceNotificationResponse> addDeviceResponse = getFromFuture(addDeviceFuture, ADD_DEVICE_TIMEOUT);
+        CompletableFuture<InternalPlcProprietaryResponse<InternalPlcProprietaryRequest<AdsAddDeviceNotificationRequest>, AdsAddDeviceNotificationResponse>> addDeviceFuture = new CompletableFuture<>();
+        channel.writeAndFlush(new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsAddDeviceNotificationRequest), addDeviceFuture));
+        InternalPlcProprietaryResponse<InternalPlcProprietaryRequest<AdsAddDeviceNotificationRequest>, AdsAddDeviceNotificationResponse> addDeviceResponse = getFromFuture(addDeviceFuture, ADD_DEVICE_TIMEOUT);
         AdsAddDeviceNotificationResponse response = addDeviceResponse.getResponse();
 
         // Abort if we got anything but a successful response.
@@ -215,7 +212,7 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
             throw new PlcRuntimeException("Error code received " + response.getResult());
         }
         AdsSubscriptionHandle adsSubscriptionHandle = new AdsSubscriptionHandle(response.getNotificationHandle());
-        future.complete(new PlcSubscriptionResponse(subscriptionRequest, Collections.singletonList(
+        future.complete(new DefaultPlcSubscriptionResponse(subscriptionRequest, Collections.singletonList(
             new SubscriptionResponseItem<>(subscriptionRequestItem, adsSubscriptionHandle, PlcResponseCode.OK))));
 
         Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer =
@@ -228,7 +225,7 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
                         Data data = adsNotificationSample.getData();
                         try {
                             @SuppressWarnings("unchecked")
-                            List<?> decodeData = LittleEndianDecoder.decodeData(datatype, data.getBytes());
+                            List<?> decodeData = LittleEndianDecoder.decodeData(adsDataType, data.getBytes());
                             SubscriptionEventItem subscriptionEventItem =
                                 new SubscriptionEventItem(subscriptionRequestItem, timeStamp, decodeData);
                             subscriptionRequestItem.getConsumer().accept(subscriptionEventItem);
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 31b9b34..f46c856 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
@@ -19,19 +19,50 @@
 package org.apache.plc4x.java.ads.model;
 
 public enum AdsDataType {
-    BIT,
-    BIT8,
-    BITARR8,
-    BITARR16,
-    BITARR32,
-    INT8,
-    INT16,
-    INT32,
-    INT64,
-    UINT8,
-    UINT16,
-    UINT32,
-    UINT64,
-    FLOAT,
-    DOUBLE
+    // https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=
+    BIT(1),
+    BIT8(1),
+    BITARR8(1),
+    BITARR16(2),
+    BITARR32(4),
+    INT8(1),
+    INT16(2),
+    INT32(4),
+    INT64(8),
+    UINT8(1),
+    UINT16(2),
+    UINT32(4),
+    UINT64(8),
+    FLOAT(4),
+    DOUBLE(8),
+    // https://infosys.beckhoff.com/english.php?content=../content/1033/tcplccontrol/html/tcplcctrl_plc_data_types_overview.htm&id
+    BOOL(0),
+    BYTE(0),
+    WORD(0),
+    DWORD(0),
+    SINT(0),
+    USINT(0),
+    INT(0),
+    UINT(0),
+    DINT(0),
+    UDINT(0),
+    LINT(0),
+    ULINT(0),
+    REAL(0),
+    LREAL(0),
+    STRING(0),
+    TIME(0),
+    TIME_OF_DAY(0),
+    DATE(0),
+    DATE_AND_TIME(0);
+
+    private final int tagetByteSize;
+
+    AdsDataType(int tagetByteSize) {
+        this.tagetByteSize = tagetByteSize;
+    }
+
+    public int getTagetByteSize() {
+        return tagetByteSize;
+    }
 }
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsField.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsField.java
index b4e8d38..e5a1822 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsField.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsField.java
@@ -47,7 +47,7 @@ public class AdsField implements PlcField {
         this.indexGroup = indexGroup;
         ByteValue.checkUnsignedBounds(indexOffset, 4);
         this.indexOffset = indexOffset;
-        this.adsDataType = adsDataType;
+        this.adsDataType = Objects.requireNonNull(adsDataType);
         this.numberOfElements = numberOfElements != null ? numberOfElements : 1;
         if (this.numberOfElements <= 0) {
             throw new IllegalArgumentException("numberOfElements must be greater then zero. Was " + this.numberOfElements);
@@ -87,11 +87,8 @@ public class AdsField implements PlcField {
         String adsDataTypeString = matcher.group("adsDataType");
         AdsDataType adsDataType = AdsDataType.valueOf(adsDataTypeString);
 
-        Integer numberOfElements = null;
         String numberOfElementsString = matcher.group("numberOfElements");
-        if (numberOfElementsString != null) {
-            numberOfElements = Integer.valueOf(numberOfElementsString);
-        }
+        Integer numberOfElements = numberOfElementsString != null ? Integer.valueOf(numberOfElementsString) : null;
 
         return new AdsField(indexGroup, indexOffset, adsDataType, numberOfElements);
     }
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/SymbolicAdsField.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/SymbolicAdsField.java
index 2437b44..b8fc06e 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/SymbolicAdsField.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/SymbolicAdsField.java
@@ -30,12 +30,21 @@ import java.util.regex.Pattern;
  */
 public class SymbolicAdsField implements PlcField {
 
-    private static final Pattern SYMBOLIC_ADDRESS_PATTERN = Pattern.compile("^(?<symbolicAddress>.+)");
+    private static final Pattern SYMBOLIC_ADDRESS_PATTERN = Pattern.compile("^(?<symbolicAddress>.+):(?<adsDataType>.+)(\\[(?<numberOfElements>\\d)])?");
 
     private final String symbolicAddress;
 
-    private SymbolicAdsField(String symbolicAddress) {
+    private final AdsDataType adsDataType;
+
+    private final int numberOfElements;
+
+    private SymbolicAdsField(String symbolicAddress, AdsDataType adsDataType, Integer numberOfElements) {
         this.symbolicAddress = Objects.requireNonNull(symbolicAddress);
+        this.adsDataType = Objects.requireNonNull(adsDataType);
+        this.numberOfElements = numberOfElements != null ? numberOfElements : 1;
+        if (this.numberOfElements <= 0) {
+            throw new IllegalArgumentException("numberOfElements must be greater then zero. Was " + this.numberOfElements);
+        }
     }
 
     public static SymbolicAdsField of(String address) throws PlcInvalidFieldException {
@@ -45,7 +54,13 @@ public class SymbolicAdsField implements PlcField {
         }
         String symbolicAddress = matcher.group("symbolicAddress");
 
-        return new SymbolicAdsField(symbolicAddress);
+        String adsDataTypeString = matcher.group("adsDataType");
+        AdsDataType adsDataType = AdsDataType.valueOf(adsDataTypeString);
+
+        String numberOfElementsString = matcher.group("numberOfElements");
+        Integer numberOfElements = numberOfElementsString != null ? Integer.valueOf(numberOfElementsString) : null;
+
+        return new SymbolicAdsField(symbolicAddress, adsDataType, numberOfElements);
     }
 
     public static boolean matches(String address) {
@@ -56,6 +71,14 @@ public class SymbolicAdsField implements PlcField {
         return symbolicAddress;
     }
 
+    public AdsDataType getAdsDataType() {
+        return adsDataType;
+    }
+
+    public int getNumberOfElements() {
+        return numberOfElements;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java
index 4f165c1..5a85640 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java
@@ -20,38 +20,43 @@ package org.apache.plc4x.java.ads.protocol;
 
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.MessageToMessageCodec;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.plc4x.java.ads.api.commands.*;
 import org.apache.plc4x.java.ads.api.commands.types.*;
 import org.apache.plc4x.java.ads.api.generic.AmsPacket;
 import org.apache.plc4x.java.ads.api.generic.types.AmsNetId;
 import org.apache.plc4x.java.ads.api.generic.types.AmsPort;
 import org.apache.plc4x.java.ads.api.generic.types.Invoke;
+import org.apache.plc4x.java.ads.model.AdsDataType;
 import org.apache.plc4x.java.ads.model.AdsField;
 import org.apache.plc4x.java.ads.model.SymbolicAdsField;
 import org.apache.plc4x.java.ads.protocol.exception.AdsException;
-import org.apache.plc4x.java.ads.protocol.util.LittleEndianDecoder;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.api.exceptions.PlcIoException;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-import org.apache.plc4x.java.api.messages.*;
+import org.apache.plc4x.java.api.messages.PlcProprietaryRequest;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcRequest;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.base.messages.InternalPlcRequest;
-import org.apache.plc4x.java.base.messages.InternalPlcResponse;
-import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.*;
+import org.apache.plc4x.java.base.messages.items.FieldItem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import static org.apache.plc4x.java.ads.protocol.util.LittleEndianDecoder.decodeData;
+import static org.apache.plc4x.java.ads.protocol.util.LittleEndianEncoder.encodeData;
 
 public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> {
 
@@ -128,7 +133,7 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
     }
 
     private void encodeWriteRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcException {
-        PlcWriteRequest writeRequest = (PlcWriteRequest) msg.getRequest();
+        InternalPlcWriteRequest writeRequest = (InternalPlcWriteRequest) msg.getRequest();
         if (writeRequest.getFields().size() != 1) {
             throw new PlcProtocolException("Only one item supported");
         }
@@ -145,7 +150,11 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
         Invoke invokeId = Invoke.of(correlationBuilder.incrementAndGet());
         IndexGroup indexGroup = IndexGroup.of(adsField.getIndexGroup());
         IndexOffset indexOffset = IndexOffset.of(adsField.getIndexOffset());
-        byte[] bytes = encodeData(adsField.getAdsDataType(), writeRequestItem.getValues().toArray());
+
+        FieldItem fieldItem = writeRequest.getFieldItems().get(0);
+        Object[] values = fieldItem.getValues();
+
+        byte[] bytes = encodeData(adsField.getAdsDataType(), values);
         Data data = Data.of(bytes);
         AmsPacket amsPacket = AdsWriteRequest.of(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, invokeId, indexGroup, indexOffset, data);
         LOGGER.debug("encoded write request {}", amsPacket);
@@ -175,19 +184,17 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
         Invoke invokeId = Invoke.of(correlationBuilder.incrementAndGet());
         IndexGroup indexGroup = IndexGroup.of(adsField.getIndexGroup());
         IndexOffset indexOffset = IndexOffset.of(adsField.getIndexOffset());
-        // TODO: length determination doesn't work here really as this is only known within the plc or by the developer
-        Length length = Length.of(calculateLength(readRequestItem.getDatatype(), readRequestItem.getSize()));
+        AdsDataType adsDataType = adsField.getAdsDataType();
+        int numberOfElements = adsField.getNumberOfElements();
+        int readLength = adsDataType.getTagetByteSize() * numberOfElements;
+        Length length = Length.of(readLength);
         AmsPacket amsPacket = AdsReadRequest.of(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, invokeId, indexGroup, indexOffset, length);
         LOGGER.debug("encoded read request {}", amsPacket);
         out.add(amsPacket);
         requests.put(invokeId.getAsLong(), msg);
     }
 
-    private long calculateLength(Class<?> dataType, int size) {
-        return LittleEndianDecoder.getLengthFor(dataType, 16) * size;
-    }
-
-    private void encodeProprietaryRequest(PlcRequestContainer<PlcRequest, PlcResponse> msg, List<Object> out) throws PlcProtocolException {
+    private void encodeProprietaryRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcProtocolException {
         PlcProprietaryRequest plcProprietaryRequest = (PlcProprietaryRequest) msg.getRequest();
         if (!(plcProprietaryRequest.getProprietaryRequest() instanceof AmsPacket)) {
             throw new PlcProtocolException("Unsupported proprietary type for this driver " + plcProprietaryRequest.getProprietaryRequest().getClass());
@@ -206,13 +213,13 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
             handleAdsDeviceNotificationRequest((AdsDeviceNotificationRequest) amsPacket);
             return;
         }
-        PlcRequestContainer<PlcRequest, PlcResponse> plcRequestContainer = requests.remove(amsPacket.getAmsHeader().getInvokeId().getAsLong());
+        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> plcRequestContainer = requests.remove(amsPacket.getAmsHeader().getInvokeId().getAsLong());
         if (plcRequestContainer == null) {
             LOGGER.info("Unmapped packet received {}", amsPacket);
             return;
         }
         PlcRequest request = plcRequestContainer.getRequest();
-        PlcResponse response = null;
+        final InternalPlcResponse response;
 
         // Handle the response to a read request.
         if (request instanceof PlcReadRequest) {
@@ -229,6 +236,8 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
             }
         } else if (request instanceof PlcProprietaryRequest) {
             response = decodeProprietaryResponse(amsPacket, plcRequestContainer);
+        } else {
+            response = null;
         }
         LOGGER.debug("Plc4x response {}", response);
 
@@ -258,37 +267,46 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
 
 
     @SuppressWarnings("unchecked")
-    private PlcResponse decodeWriteResponse(AdsWriteResponse responseMessage, PlcRequestContainer<PlcRequest, PlcResponse> requestContainer) {
-        PlcWriteRequest plcWriteRequest = (PlcWriteRequest) requestContainer.getRequest();
-        PlcWriteRequestItem requestItem = plcWriteRequest.getRequestItems().get(0);
-
+    private InternalPlcResponse decodeWriteResponse(AdsWriteResponse responseMessage, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> requestContainer) {
+        InternalPlcWriteRequest plcWriteRequest = (InternalPlcWriteRequest) requestContainer.getRequest();
         PlcResponseCode responseCode = decodeResponseCode(responseMessage.getResult());
 
-        if (plcWriteRequest instanceof TypeSafePlcWriteRequest) {
-            return new TypeSafePlcWriteResponse((TypeSafePlcWriteRequest) plcWriteRequest, Collections.singletonList(new PlcWriteResponseItem<>(requestItem, responseCode)));
-        } else {
-            return new PlcWriteResponse(plcWriteRequest, Collections.singletonList(new PlcWriteResponseItem<>(requestItem, responseCode)));
-        }
+        // TODO: does every item has the same ads response or is this whole aggregation broken?
+        Map<String, PlcResponseCode> responseItems = plcWriteRequest.getFieldNames()
+            .stream()
+            .collect(Collectors.toMap(
+                fieldName -> fieldName,
+                __ -> responseCode
+            ));
+        return new DefaultPlcWriteResponse(plcWriteRequest, responseItems);
     }
 
     @SuppressWarnings("unchecked")
-    private PlcResponse decodeReadResponse(AdsReadResponse responseMessage, PlcRequestContainer<PlcRequest, PlcResponse> requestContainer) throws PlcProtocolException {
-        PlcReadRequest plcReadRequest = (PlcReadRequest) requestContainer.getRequest();
-        PlcReadRequestItem requestItem = plcReadRequest.getRequestItems().get(0);
+    private InternalPlcResponse decodeReadResponse(AdsReadResponse responseMessage, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> requestContainer) throws PlcProtocolException {
+        InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest();
+
+        // TODO: only single requests supported for now
+        AdsField field = (AdsField) plcReadRequest.getFields().get(0);
+
 
         PlcResponseCode responseCode = decodeResponseCode(responseMessage.getResult());
         byte[] bytes = responseMessage.getData().getBytes();
-        List decoded = decodeData(requestItem.getDatatype(), bytes);
+        FieldItem<?> fieldItem = decodeData(field.getAdsDataType(), bytes);
 
-        if (plcReadRequest instanceof TypeSafePlcReadRequest) {
-            return new TypeSafePlcReadResponse((TypeSafePlcReadRequest) plcReadRequest, Collections.singletonList(new PlcReadResponseItem<>(requestItem, responseCode, decoded)));
-        } else {
-            return new PlcReadResponse(plcReadRequest, Collections.singletonList(new PlcReadResponseItem<>(requestItem, responseCode, decoded)));
-        }
+        // TODO: does every item has the same ads response or is this whole aggregation broken?
+        Map<String, Pair<PlcResponseCode, FieldItem>> responseItems = plcReadRequest.getFieldNames()
+            .stream()
+            .collect(Collectors.toMap(
+                fieldName -> fieldName,
+                __ -> Pair.of(responseCode, fieldItem)
+            ));
+
+        return new DefaultPlcReadResponse(plcReadRequest, responseItems);
     }
 
-    private PlcResponse decodeProprietaryResponse(AmsPacket amsPacket, PlcRequestContainer<PlcRequest, PlcResponse> plcRequestContainer) {
-        return new PlcProprietaryResponse<>((PlcProprietaryRequest) plcRequestContainer.getRequest(), amsPacket);
+    @SuppressWarnings("unchecked")
+    private InternalPlcResponse decodeProprietaryResponse(AmsPacket amsPacket, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> plcRequestContainer) {
+        return new DefaultPlcProprietaryResponse<>((InternalPlcProprietaryRequest) plcRequestContainer.getRequest(), amsPacket);
     }
 
     private PlcResponseCode decodeResponseCode(Result result) {
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 a0fb491..38e3d03 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,10 +18,16 @@
  */
 package org.apache.plc4x.java.ads.protocol.util;
 
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.NotImplementedException;
 import org.apache.plc4x.java.ads.api.commands.types.TimeStamp;
+import org.apache.plc4x.java.ads.model.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
+import org.apache.plc4x.java.base.messages.items.BooleanFieldItem;
+import org.apache.plc4x.java.base.messages.items.FieldItem;
+import org.apache.plc4x.java.base.messages.items.IntegerFieldItem;
 
 import java.math.BigInteger;
 import java.util.*;
@@ -56,7 +62,135 @@ public class LittleEndianDecoder {
     }
 
     @SuppressWarnings("unchecked")
-    public static <T> List<T> decodeData(Class<T> dataType, byte[] adsData) throws PlcProtocolException {
+    public static FieldItem<?> decodeData(AdsDataType adsDataType, byte[] adsData) {
+        ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(adsData);
+        switch (adsDataType) {
+            case BIT: {
+                LinkedList<Boolean> values = new LinkedList<>();
+                while (wrappedBuffer.isReadable()) {
+                    short aByte = wrappedBuffer.readUnsignedByte();
+                    values.offer(aByte != 0);
+                }
+                return new BooleanFieldItem(values.toArray(new Boolean[0]));
+            }
+            case BIT8: {
+                LinkedList<Boolean> values = new LinkedList<>();
+                while (wrappedBuffer.isReadable()) {
+                    short aByte = wrappedBuffer.readUnsignedByte();
+                    values.offer(aByte != 0);
+                }
+                return new BooleanFieldItem(values.toArray(new Boolean[0]));
+            }
+            case BITARR8: {
+                LinkedList<Long> values = new LinkedList<>();
+                while (wrappedBuffer.isReadable()) {
+                    short aByte = wrappedBuffer.readUnsignedByte();
+                    values.offer((long) aByte);
+                }
+                return new IntegerFieldItem(values.toArray(new Long[0]));
+            }
+            case BITARR16: {
+                LinkedList<Long> values = new LinkedList<>();
+                while (wrappedBuffer.isReadable()) {
+                    long aLong = wrappedBuffer.readUnsignedIntLE();
+                    values.offer(aLong);
+                }
+                return new IntegerFieldItem(values.toArray(new Long[0]));
+            }
+            case BITARR32: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case INT8: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case INT16: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case INT32: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case INT64: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UINT8: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UINT16: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UINT32: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UINT64: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case FLOAT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case DOUBLE: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case BOOL: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case BYTE: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case WORD: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case DWORD: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case SINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case USINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case INT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case DINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case UDINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case LINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case ULINT: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case REAL: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case LREAL: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case STRING: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case TIME: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case TIME_OF_DAY: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case DATE: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            case DATE_AND_TIME: {
+                throw new NotImplementedException("not implemented yet " + adsDataType);
+            }
+            default:
+                throw new IllegalArgumentException("Unsupported adsDataType " + adsDataType);
+        }
+        /*
         if (dataType == byte[].class) {
             return (List<T>) Collections.singletonList(adsData);
         }
@@ -122,6 +256,7 @@ public class LittleEndianDecoder {
             }
         }
         return (List<T>) result;
+        */
     }
 
     private static int decodeString(byte[] adsData, int i, int length, List<Object> result) throws PlcProtocolException {
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 a66fa0b..c09298b 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
@@ -20,6 +20,7 @@ package org.apache.plc4x.java.ads.protocol.util;
 
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.plc4x.java.ads.api.commands.types.TimeStamp;
+import org.apache.plc4x.java.ads.model.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
@@ -41,33 +42,34 @@ public class LittleEndianEncoder {
     }
 
     // TODO: add bound checking
-    public static byte[] encodeData(Class<?> valueType, Object... values) throws PlcProtocolException {
+    public static byte[] encodeData(AdsDataType adsDataType, Object... values) throws PlcProtocolException {
         if (values.length == 0) {
             return new byte[]{};
         }
+        Class<?> valueType = values[0].getClass();
         Stream<byte[]> result;
         if (valueType == Boolean.class) {
-            result = encodeBoolean(Arrays.stream(values).map(Boolean.class::cast));
+            result = encodeBoolean(adsDataType, Arrays.stream(values).map(Boolean.class::cast));
         } else if (valueType == Byte.class) {
-            result = encodeByte(Arrays.stream(values).map(Byte.class::cast));
+            result = encodeByte(adsDataType, Arrays.stream(values).map(Byte.class::cast));
         } else if (valueType == Short.class) {
-            result = encodeShort(Arrays.stream(values).map(Short.class::cast));
+            result = encodeShort(adsDataType, Arrays.stream(values).map(Short.class::cast));
         } else if (valueType == Integer.class) {
-            result = encodeInteger(Arrays.stream(values).map(Integer.class::cast));
+            result = encodeInteger(adsDataType, Arrays.stream(values).map(Integer.class::cast));
         } else if (valueType == BigInteger.class) {
-            result = encodeBigInteger(Arrays.stream(values).map(BigInteger.class::cast));
+            result = encodeBigInteger(adsDataType, 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));
+            result = encodeCalendar(adsDataType, Arrays.stream(values).map(Calendar.class::cast));
         } else if (valueType == Float.class) {
-            result = encodeFloat(Arrays.stream(values).map(Float.class::cast));
+            result = encodeFloat(adsDataType, Arrays.stream(values).map(Float.class::cast));
         } else if (valueType == Double.class) {
-            result = encodeDouble(Arrays.stream(values).map(Double.class::cast));
+            result = encodeDouble(adsDataType, Arrays.stream(values).map(Double.class::cast));
         } else if (valueType == String.class) {
-            result = encodeString(Arrays.stream(values).map(String.class::cast));
+            result = encodeString(adsDataType, Arrays.stream(values).map(String.class::cast));
         } else if (valueType == byte[].class) {
-            result = encodeByteArray(Arrays.stream(values).map(byte[].class::cast));
+            result = encodeByteArray(adsDataType, Arrays.stream(values).map(byte[].class::cast));
         } else if (valueType == Byte[].class) {
-            result = encodeBigByteArray(Arrays.stream(values).map(Byte[].class::cast));
+            result = encodeBigByteArray(adsDataType, Arrays.stream(values).map(Byte[].class::cast));
         } else {
             throw new PlcUnsupportedDataTypeException(valueType);
         }
@@ -90,7 +92,8 @@ public class LittleEndianEncoder {
         }
     }
 
-    private static Stream<byte[]> encodeString(Stream<String> stringStream) {
+    private static Stream<byte[]> encodeString(AdsDataType adsDataType, Stream<String> stringStream) {
+        // TODO: add boundchecks and add optional extension
         // TODO: what do we do with utf-8 values with 2 bytes? what is the charset here?
         return stringStream
             .map(s -> s.getBytes(Charset.defaultCharset()))
@@ -98,15 +101,18 @@ public class LittleEndianEncoder {
             .map(bytes -> ArrayUtils.add(bytes, (byte) 0x0));
     }
 
-    private static Stream<byte[]> encodeByteArray(Stream<byte[]> byteArrayStream) {
+    private static Stream<byte[]> encodeByteArray(AdsDataType adsDataType, Stream<byte[]> byteArrayStream) {
+        // TODO: add boundchecks and add optional extension
         return byteArrayStream;
     }
 
-    private static Stream<byte[]> encodeBigByteArray(Stream<Byte[]> byteArrayStream) {
+    private static Stream<byte[]> encodeBigByteArray(AdsDataType adsDataType, Stream<Byte[]> byteArrayStream) {
+        // TODO: add boundchecks and add optional extension
         return byteArrayStream.map(ArrayUtils::toPrimitive);
     }
 
-    private static Stream<byte[]> encodeFloat(Stream<Float> floatStream) {
+    private static Stream<byte[]> encodeFloat(AdsDataType adsDataType, Stream<Float> floatStream) {
+        // TODO: add boundchecks and add optional extension
         return floatStream
             // TODO: check how ads expects this data
             .map(Float::floatToIntBits)
@@ -118,7 +124,8 @@ public class LittleEndianEncoder {
             });
     }
 
-    private static Stream<byte[]> encodeDouble(Stream<Double> doubleStream) {
+    private static Stream<byte[]> encodeDouble(AdsDataType adsDataType, Stream<Double> doubleStream) {
+        // TODO: add boundchecks and add optional extension
         return doubleStream
             // TODO: check how ads expects this data
             .map(Double::doubleToLongBits)
@@ -134,7 +141,8 @@ public class LittleEndianEncoder {
             });
     }
 
-    private static Stream<byte[]> encodeInteger(Stream<Integer> integerStream) {
+    private static Stream<byte[]> encodeInteger(AdsDataType adsDataType, Stream<Integer> integerStream) {
+        // TODO: add boundchecks and add optional extension
         return integerStream
             .map(intValue -> new byte[]{
                 (byte) (intValue & 0x000000ff),
@@ -144,7 +152,8 @@ public class LittleEndianEncoder {
             });
     }
 
-    private static Stream<byte[]> encodeBigInteger(Stream<BigInteger> bigIntegerStream) {
+    private static Stream<byte[]> encodeBigInteger(AdsDataType adsDataType, Stream<BigInteger> bigIntegerStream) {
+        // TODO: add boundchecks and add optional extension
         return bigIntegerStream
             .map(bigIntValue -> {
                 byte[] bytes = bigIntValue.toByteArray();
@@ -159,7 +168,8 @@ public class LittleEndianEncoder {
             });
     }
 
-    private static Stream<byte[]> encodeCalendar(Stream<Calendar> calendarStream) {
+    private static Stream<byte[]> encodeCalendar(AdsDataType adsDataType, Stream<Calendar> calendarStream) {
+        // TODO: add boundchecks and add optional extension
         return calendarStream
             .map(Calendar.class::cast)
             .map(Calendar::getTime)
@@ -181,7 +191,8 @@ public class LittleEndianEncoder {
     }
 
 
-    private static Stream<byte[]> encodeShort(Stream<Short> shortStream) {
+    private static Stream<byte[]> encodeShort(AdsDataType adsDataType, Stream<Short> shortStream) {
+        // TODO: add boundchecks and add optional extension
         return shortStream
             .map(shortValue -> new byte[]{
                 (byte) (shortValue & 0x00ff),
@@ -189,12 +200,14 @@ public class LittleEndianEncoder {
             });
     }
 
-    private static Stream<byte[]> encodeByte(Stream<Byte> byteStream) {
+    private static Stream<byte[]> encodeByte(AdsDataType adsDataType, Stream<Byte> byteStream) {
+        // TODO: add boundchecks and add optional extension
         return byteStream
             .map(aByte -> new byte[]{aByte});
     }
 
-    private static Stream<byte[]> encodeBoolean(Stream<Boolean> booleanStream) {
+    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});
     }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryRequest.java
index eb9715c..fa716f0 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryRequest.java
@@ -18,9 +18,7 @@
  */
 package org.apache.plc4x.java.base.messages;
 
-import org.apache.plc4x.java.api.messages.PlcProprietaryRequest;
-
-public class DefaultPlcProprietaryRequest<REQUEST> implements PlcProprietaryRequest<REQUEST> {
+public class DefaultPlcProprietaryRequest<REQUEST> implements InternalPlcProprietaryRequest<REQUEST> {
 
     private REQUEST proprietaryRequest;
 
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryResponse.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryResponse.java
index a459866..679fde1 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryResponse.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcProprietaryResponse.java
@@ -18,16 +18,13 @@
  */
 package org.apache.plc4x.java.base.messages;
 
-import org.apache.plc4x.java.api.messages.PlcProprietaryRequest;
-import org.apache.plc4x.java.api.messages.PlcProprietaryResponse;
+public class DefaultPlcProprietaryResponse<REQUEST, RESPONSE> implements InternalPlcProprietaryResponse<REQUEST, RESPONSE> {
 
-public class DefaultPlcProprietaryResponse<REQUEST, RESPONSE> implements PlcProprietaryResponse<REQUEST, RESPONSE> {
-
-    private final PlcProprietaryRequest<REQUEST> plcProprietaryRequest;
+    private final InternalPlcProprietaryRequest<REQUEST> plcProprietaryRequest;
 
     private final RESPONSE proprietaryResponse;
 
-    public DefaultPlcProprietaryResponse(PlcProprietaryRequest<REQUEST> plcProprietaryRequest, RESPONSE proprietaryResponse) {
+    public DefaultPlcProprietaryResponse(InternalPlcProprietaryRequest<REQUEST> plcProprietaryRequest, RESPONSE proprietaryResponse) {
         this.plcProprietaryRequest = plcProprietaryRequest;
         this.proprietaryResponse = proprietaryResponse;
     }
@@ -38,7 +35,7 @@ public class DefaultPlcProprietaryResponse<REQUEST, RESPONSE> implements PlcProp
     }
 
     @Override
-    public PlcProprietaryRequest<REQUEST> getRequest() {
+    public InternalPlcProprietaryRequest getRequest() {
         return plcProprietaryRequest;
     }
 }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcSubscriptionRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcSubscriptionRequest.java
index b6b3a3d..2a50cc4 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcSubscriptionRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcSubscriptionRequest.java
@@ -18,10 +18,10 @@ under the License.
 */
 package org.apache.plc4x.java.base.messages;
 
-import org.apache.plc4x.java.api.messages.PlcMessageBuilder;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.model.PlcField;
 
+import java.time.Duration;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 
@@ -48,8 +48,28 @@ public class DefaultPlcSubscriptionRequest implements InternalPlcSubscriptionReq
     }
 
     @Override
-    public PlcMessageBuilder<PlcSubscriptionRequest> builder() {
-        return null;
+    public Builder builder() {
+        return new Builder() {
+            @Override
+            public Builder addCyclicField(String name, String fieldQuery, Duration pollingInterval) {
+                return null;
+            }
+
+            @Override
+            public Builder addChangeOfStateField(String name, String fieldQuery) {
+                return null;
+            }
+
+            @Override
+            public Builder addEventField(String name, String fieldQuery) {
+                return null;
+            }
+
+            @Override
+            public PlcSubscriptionRequest build() {
+                return null;
+            }
+        };
     }
 
 }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java
index 888c5a6..218d61e 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java
@@ -59,7 +59,7 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest {
 
     @Override
     public LinkedList<PlcField> getFields() {
-        return new LinkedList<>(fields.values().stream().map(Pair::getKey).collect(Collectors.toList()));
+        return fields.values().stream().map(Pair::getKey).collect(Collectors.toCollection(LinkedList::new));
     }
 
     public FieldItem getFieldItem(String name) {
@@ -67,6 +67,11 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest {
     }
 
     @Override
+    public LinkedList<FieldItem> getFieldItems() {
+        return fields.values().stream().map(Pair::getValue).collect(Collectors.toCollection(LinkedList::new));
+    }
+
+    @Override
     public int getNumberOfValues(String name) {
         return fields.get(name).getValue().getNumValues();
     }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryRequest.java
similarity index 82%
copy from plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
copy to plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryRequest.java
index 2a6b03d..3e2ed9f 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryRequest.java
@@ -18,8 +18,7 @@
  */
 package org.apache.plc4x.java.base.messages;
 
-import org.apache.plc4x.java.api.messages.PlcWriteRequest;
-
-public interface InternalPlcWriteRequest extends PlcWriteRequest, InternalPlcRequest {
+import org.apache.plc4x.java.api.messages.PlcProprietaryRequest;
 
+public interface InternalPlcProprietaryRequest<REQUEST> extends PlcProprietaryRequest<REQUEST>, InternalPlcRequest {
 }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryResponse.java
similarity index 74%
copy from plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
copy to plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryResponse.java
index 2a6b03d..eb5aa3b 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcProprietaryResponse.java
@@ -18,8 +18,7 @@
  */
 package org.apache.plc4x.java.base.messages;
 
-import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcProprietaryResponse;
 
-public interface InternalPlcWriteRequest extends PlcWriteRequest, InternalPlcRequest {
-
-}
+public interface InternalPlcProprietaryResponse<REQUEST, RESPONSE> extends PlcProprietaryResponse<InternalPlcProprietaryRequest<REQUEST>, RESPONSE>, InternalPlcResponse<InternalPlcProprietaryRequest<REQUEST>> {
+}
\ No newline at end of file
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
index 2a6b03d..a4bad51 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/InternalPlcWriteRequest.java
@@ -19,7 +19,13 @@
 package org.apache.plc4x.java.base.messages;
 
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.base.messages.items.FieldItem;
+
+import java.util.LinkedList;
 
 public interface InternalPlcWriteRequest extends PlcWriteRequest, InternalPlcRequest {
 
+    FieldItem getFieldItem(String name);
+
+    LinkedList<FieldItem> getFieldItems();
 }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
index 38a1694..1ce4134 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
@@ -111,7 +111,7 @@ public abstract class FieldItem<T> {
         return null;
     }
 
-    protected T[] getValues() {
+    public T[] getValues() {
         return values;
     }