You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/10/29 18:18:57 UTC

[plc4x] 02/03: - Major refactoring regarding the FieldHandlers, ValueHandlers - Refactored out all of the "Internal" interfaces

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

cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit e1a97c99c23866d1d718ff563826fd4d6e461574
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Oct 29 19:16:29 2020 +0100

    - Major refactoring regarding the FieldHandlers, ValueHandlers
    - Refactored out all of the "Internal" interfaces
---
 .../resources/templates/java/data-io-template.ftlh |   3 +-
 .../api/messages/PlcSubscriptionFieldRequest.java} |  23 +-
 .../messages/PlcSubscriptionFieldResponse.java}    |  25 +-
 .../java/api/messages/PlcSubscriptionRequest.java  |   3 +-
 .../java/api/messages/PlcSubscriptionResponse.java |   2 +-
 .../api/messages/PlcUnsubscriptionRequest.java     |   3 +
 .../plc4x/java/api/messages/PlcWriteRequest.java   |  13 +-
 .../java/api/model/PlcConsumerRegistration.java    |  12 +
 .../java/api/model/PlcSubscriptionField.java}      |  39 +-
 .../java/api/model/PlcSubscriptionHandle.java      |   8 +-
 .../org/apache/plc4x/java/abeth/AbEthDriver.java   |   2 +-
 .../plc4x/java/abeth/field/AbEthFieldHandler.java  |   4 +-
 .../java/abeth/protocol/AbEthProtocolLogic.java    |   6 +-
 .../java/abeth/protocol/Plc4xAbEthProtocol.java    |   5 +-
 plc4j/drivers/ads/pom.xml                          |  25 -
 .../org/apache/plc4x/java/ads/ADSPlcDriver.java    |   2 +-
 .../org/apache/plc4x/java/ads/field/AdsField.java  |   3 +-
 .../plc4x/java/ads/field/AdsFieldHandler.java      |  17 +-
 .../plc4x/java/ads/field/DirectAdsField.java       |  25 +
 .../plc4x/java/ads/field/SymbolicAdsField.java     |  21 +
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  |  17 +-
 .../attic/connection/AdsAbstractPlcConnection.java | 232 -------
 .../attic/connection/AdsConnectionFactory.java     |  58 --
 .../attic/connection/AdsSerialPlcConnection.java   |  60 --
 .../attic/connection/AdsTcpPlcConnection.java      | 370 ------------
 .../amsads/attic/protocol/Ads2PayloadProtocol.java |  93 ---
 .../attic/protocol/Payload2SerialProtocol.java     | 114 ----
 .../amsads/attic/protocol/Payload2TcpProtocol.java |  93 ---
 .../amsads/attic/protocol/Plc4x2AdsProtocol.java   | 334 ----------
 .../attic/protocol/exception/AdsException.java     |  56 --
 .../exception/AdsProtocolOverflowException.java    |  32 -
 .../amsads/attic/protocol/util/DigestUtil.java     |  46 --
 .../attic/protocol/util/LittleEndianDecoder.java   | 489 ---------------
 .../attic/protocol/util/LittleEndianEncoder.java   | 285 ---------
 .../protocol/util/SingleMessageRateLimiter.java    | 124 ----
 .../plc4x/java/amsads/attic/types/AdsDataType.java | 578 ------------------
 .../apache/plc4x/java/eip/readwrite/EIPDriver.java |   2 +-
 .../java/eip/readwrite/field/EipFieldHandler.java  |  14 +-
 .../eip/readwrite/protocol/EipProtocolLogic.java   |  13 +-
 .../java/firmata/readwrite/FirmataDriver.java      |   2 +-
 .../readwrite/context/FirmataDriverContext.java    |   6 +-
 .../readwrite/field/FirmataFieldHandler.java       |  11 +-
 .../readwrite/protocol/FirmataProtocolLogic.java   |  14 +-
 .../apache/plc4x/java/knxnetip/KnxNetIpDriver.java |   2 +-
 .../java/knxnetip/field/KnxNetIpFieldHandler.java  |   9 +-
 .../knxnetip/protocol/KnxNetIpProtocolLogic.java   |   9 +-
 .../plc4x/java/mock/connection/MockConnection.java |   3 +-
 .../plc4x/java/mock/field/MockFieldHandler.java    |  70 +--
 .../apache/plc4x/java/mock/field/MockPlcValue.java |   9 +-
 .../plc4x/java/mock/field/MockValueHandler.java}   |  17 +-
 .../org/apache/plc4x/java/modbus/ModbusDriver.java |   2 +-
 .../plc4x/java/modbus/field/ModbusField.java       |  25 +-
 .../java/modbus/field/ModbusFieldHandler.java      |  15 +-
 .../java/modbus/protocol/ModbusProtocolLogic.java  |   4 +-
 .../apache/plc4x/java/modbus/ModbusEncodeTest.java |  38 +-
 ...IOTest.java => ModbusParserSerializerTest.java} |   4 +-
 .../opcua/connection/BaseOpcuaPlcConnection.java   |   3 +-
 .../opcua/connection/OpcuaTcpPlcConnection.java    | 159 +++--
 .../java/opcua/protocol/OpcuaPlcFieldHandler.java  |  21 +-
 .../opcua/protocol/OpcuaSubsriptionHandle.java     |   5 +-
 .../apache/plc4x/java/opcua/ManualPLC4XOpcua.java  |   4 +-
 .../plc4x/java/opcua/OpcuaPlcDriverTest.java       |   2 +-
 .../apache/plc4x/java/s7/readwrite/S7Driver.java   |   4 +-
 .../plc4x/java/s7/readwrite/field/S7Field.java     |  37 +-
 .../java/s7/readwrite/field/S7PlcFieldHandler.java |  68 +--
 .../java/s7/readwrite/field/S7StringField.java     |  12 +
 .../s7/readwrite/protocol/S7ProtocolLogic.java     |  18 +-
 .../java/s7/readwrite/value/S7ValueHandler.java    |  51 --
 .../simulated/connection/SimulatedConnection.java  |  78 +--
 .../java/simulated/connection/SimulatedDevice.java |  21 +-
 .../simulated/field/SimulatedFieldHandler.java     |  63 +-
 .../connection/SimulatedConnectionTest.java        |  30 +-
 .../simulated/connection/SimulatedDeviceTest.java  |   2 +-
 .../simulated/field/SimularedFieldHandlerTest.java |   4 +-
 .../dummydriver/connection/DummyConnection.java    |   2 -
 .../watertank/service/WaterTankService.java        |   2 +-
 .../examples/hellowebservice/HelloWebservice.java  |   4 +-
 .../java/org/apache/plc4x/camel/MockDriver.java    |   3 +-
 .../java/spi/connection/AbstractPlcConnection.java |  29 +-
 .../plc4x/java/spi/connection/ChannelFactory.java  |   2 -
 .../spi/connection/DefaultNettyPlcConnection.java  |  15 -
 .../spi/connection/DefaultPlcFieldHandler.java     |  40 --
 .../java/spi/connection/NettyChannelFactory.java   |  44 --
 .../plc4x/java/spi/connection/PlcFieldHandler.java |   4 +-
 .../connection/SingleProtocolStackConfigurer.java  |   3 +-
 .../exceptions/InternalPlcRuntimeException.java    |  41 --
 .../spi/messages/DefaultPlcProprietaryRequest.java |  50 --
 .../messages/DefaultPlcProprietaryResponse.java    |  49 --
 .../java/spi/messages/DefaultPlcReadRequest.java   |  26 +-
 .../java/spi/messages/DefaultPlcReadResponse.java  |  37 +-
 .../spi/messages/DefaultPlcSubscriptionEvent.java  |   5 +-
 .../messages/DefaultPlcSubscriptionRequest.java    |  55 +-
 .../messages/DefaultPlcSubscriptionResponse.java   |  19 +-
 .../messages/DefaultPlcUnsubscriptionRequest.java  |  35 +-
 .../messages/DefaultPlcUnsubscriptionResponse.java |  15 +-
 .../java/spi/messages/DefaultPlcWriteRequest.java  |  78 +--
 .../java/spi/messages/DefaultPlcWriteResponse.java |  22 +-
 .../java/spi/messages/InternalPlcFieldRequest.java |  33 -
 .../spi/messages/InternalPlcFieldResponse.java     |  28 -
 .../java/spi/messages/InternalPlcMessage.java      |  26 -
 .../messages/InternalPlcProprietaryRequest.java    |  25 -
 .../messages/InternalPlcProprietaryResponse.java   |  25 -
 .../java/spi/messages/InternalPlcReadRequest.java  |  28 -
 .../java/spi/messages/InternalPlcReadResponse.java |  33 -
 .../java/spi/messages/InternalPlcRequest.java      |  26 -
 .../java/spi/messages/InternalPlcResponse.java     |  27 -
 .../spi/messages/InternalPlcSubscriptionEvent.java |  27 -
 .../messages/InternalPlcSubscriptionRequest.java   |  38 --
 .../messages/InternalPlcSubscriptionResponse.java  |  31 -
 .../messages/InternalPlcUnsubscriptionRequest.java |  31 -
 .../java/spi/messages/InternalPlcWriteRequest.java |  38 --
 .../plc4x/java/spi/messages/PlcRawMessage.java     |  48 --
 .../java/spi/messages/PlcRequestContainer.java     |   5 +-
 .../java/spi/messages/utils/ResponseItem.java      |  15 +-
 .../spi/model/DefaultPlcConsumerRegistration.java  |  14 +-
 ...Field.java => DefaultPlcSubscriptionField.java} |   5 +-
 .../spi/model/DefaultPlcSubscriptionHandle.java    |   3 +-
 .../spi/model/InternalPlcConsumerRegistration.java |  32 -
 .../spi/model/InternalPlcSubscriptionHandle.java   |  25 -
 .../plc4x/java/spi/optimizer/BaseOptimizer.java    |   6 +-
 .../SingleItemToSingleRequestProtocol.java         | 672 ---------------------
 .../apache/plc4x/java/spi/request/PlcRequest.java  |  28 -
 .../plc4x/java/spi/utils/XmlSerializable.java}     |  10 +-
 .../java/spi/values}/IEC61131ValueHandler.java     |  15 +-
 .../org/apache/plc4x/java/spi/values}/PlcBOOL.java |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcBYTE.java |   2 +-
 .../plc4x/java/spi/values}/PlcBigDecimal.java      |   8 +-
 .../plc4x/java/spi/values}/PlcBigInteger.java      |   8 +-
 .../org/apache/plc4x/java/spi/values}/PlcCHAR.java |  32 +-
 .../org/apache/plc4x/java/spi/values}/PlcDINT.java |   2 +-
 .../apache/plc4x/java/spi/values}/PlcDWORD.java    |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcDate.java |   8 +-
 .../apache/plc4x/java/spi/values}/PlcDateTime.java |   8 +-
 .../apache/plc4x/java/spi/values}/PlcIECValue.java |  14 +-
 .../org/apache/plc4x/java/spi/values}/PlcINT.java  |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcLINT.java |   2 +-
 .../apache/plc4x/java/spi/values}/PlcLREAL.java    |   2 +-
 .../apache/plc4x/java/spi/values}/PlcLWORD.java    |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcList.java |  26 +-
 .../org/apache/plc4x/java/spi/values}/PlcNull.java |   4 +-
 .../org/apache/plc4x/java/spi/values}/PlcREAL.java |   9 +-
 .../org/apache/plc4x/java/spi/values}/PlcSINT.java |   2 +-
 .../apache/plc4x/java/spi/values}/PlcSTRING.java   |   8 +-
 .../plc4x/java/spi/values}/PlcSimpleValue.java     |   3 +-
 .../apache/plc4x/java/spi/values}/PlcStruct.java   |  23 +-
 .../org/apache/plc4x/java/spi/values}/PlcTime.java |   8 +-
 .../apache/plc4x/java/spi/values}/PlcUDINT.java    |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcUINT.java |   2 +-
 .../apache/plc4x/java/spi/values}/PlcULINT.java    |   2 +-
 .../apache/plc4x/java/spi/values}/PlcUSINT.java    |   2 +-
 .../plc4x/java/spi/values}/PlcValueAdapter.java    |   6 +-
 .../apache/plc4x/java/spi/values}/PlcValues.java   |   3 +-
 .../apache/plc4x/java/spi/values}/PlcWCHAR.java    |   2 +-
 .../org/apache/plc4x/java/spi/values}/PlcWORD.java |   4 +-
 .../apache/plc4x/java/opm/ConnectedEntityTest.java |   2 +-
 .../java/opm/PlcEntityManagerComplexTest.java      |  28 +-
 .../plc4x/java/opm/PlcEntityManagerTest.java       |   2 +-
 .../apache/plc4x/java/scraper/ScraperTaskTest.java |   2 +-
 .../org/apache/plc4x/java/scraper/ScraperTest.java |   2 +-
 .../triggeredscraper/TriggeredScraperImplTest.java |   4 +-
 .../plc4x/test/driver/DriverTestsuiteRunner.java   |  37 +-
 .../resources/protocols/ads/DriverTestsuite.xml    | 174 +++---
 .../resources/protocols/modbus/DriverTestsuite.xml | 109 +++-
 .../protocols/modbus/ParserSerializerTestsuite.xml |  44 +-
 .../resources/protocols/s7/DriverTestsuite.xml     |  70 ++-
 .../java/discovery/DiscoveryFieldHandler.java      |   4 +-
 .../java/examples/helloinflux/HelloInflux.java     |   1 +
 .../testing/protocols/modbus/DriverTestsuite.xml   | 109 +++-
 .../protocols/modbus/ParserSerializerTestsuite.xml |  44 +-
 .../testing/protocols/s7/DriverTestsuite.xml       |  70 ++-
 .../internal/plc4go/testutils/DriverTestRunner.go  |   4 +-
 .../apache/plc4x/java/bacnetip/BacNetIpDriver.java |   2 +
 .../plc4x/java/bacnetip/ede/model/Datapoint.java   |   4 +
 .../java/bacnetip/field/BacNetIpFieldHandler.java  |   4 +-
 .../bacnetip/protocol/BacNetIpProtocolLogic.java   |  11 +-
 .../java/bacnetip/PassiveBacNetIpDriverManual.java |   2 +-
 .../org/apache/plc4x/java/df1/DF1PlcDriver.java    |   2 +
 .../plc4x/java/df1/field/Df1FieldHandler.java      |   7 +-
 .../plc4x/java/df1/protocol/Plc4XDf1Protocol.java  |   8 +-
 179 files changed, 1289 insertions(+), 5604 deletions(-)

diff --git a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
index 9291fdc..218393a 100644
--- a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
@@ -73,6 +73,7 @@ import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WriteBuffer;
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
 import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+import org.apache.plc4x.java.spi.values.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -105,7 +106,7 @@ public class ${type.name}IO {
             if(${helper.toParseExpression(field, field.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) {
                 throw new ParseException("Array count of " + (${helper.toParseExpression(field, field.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
             }
-            List<Plc${case.name}> ${field.name};
+            List<PlcValue> ${field.name};
             {
                 int itemCount = (int) ${helper.toParseExpression(field, field.loopExpression, type.parserArguments)};
                 ${field.name} = new LinkedList<>();
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldRequest.java
similarity index 62%
rename from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionResponse.java
rename to plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldRequest.java
index d598600..5dee291 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionResponse.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldRequest.java
@@ -16,12 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.spi.messages;
+package org.apache.plc4x.java.api.messages;
 
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcUnsubscriptionResponse extends PlcUnsubscriptionResponse, InternalPlcResponse {
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public interface PlcSubscriptionFieldRequest extends PlcRequest {
+
+    @Override
+    CompletableFuture<? extends PlcSubscriptionFieldResponse> execute();
+
+    int getNumberOfFields();
+
+    LinkedHashSet<String> getFieldNames();
+
+    PlcSubscriptionField getField(String name);
+
+    List<PlcSubscriptionField> getFields();
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldResponse.java
similarity index 62%
rename from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteResponse.java
rename to plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldResponse.java
index 472ba1a..fb99382 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteResponse.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionFieldResponse.java
@@ -16,15 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.spi.messages;
+package org.apache.plc4x.java.api.messages;
 
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcWriteResponse;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 
-import java.util.Map;
+import java.util.Collection;
+
+/**
+ * Base type for all response messages sent as response for a prior request
+ * from a plc to the plc4x system.
+ */
+public interface PlcSubscriptionFieldResponse extends PlcResponse {
+
+    @Override
+    PlcSubscriptionFieldRequest getRequest();
+
+    Collection<String> getFieldNames();
+
+    PlcSubscriptionField getField(String name);
+
+    PlcResponseCode getResponseCode(String name);
 
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcWriteResponse extends PlcWriteResponse, InternalPlcResponse {
-    Map<String, PlcResponseCode> getValues();
 }
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 0b53e85..39f5d7f 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
@@ -21,7 +21,7 @@ package org.apache.plc4x.java.api.messages;
 import java.time.Duration;
 import java.util.concurrent.CompletableFuture;
 
-public interface PlcSubscriptionRequest extends PlcFieldRequest {
+public interface PlcSubscriptionRequest extends PlcSubscriptionFieldRequest {
 
     @Override
     CompletableFuture<? extends PlcSubscriptionResponse> execute();
@@ -62,6 +62,7 @@ public interface PlcSubscriptionRequest extends PlcFieldRequest {
          * @return builder.
          */
         PlcSubscriptionRequest.Builder addEventField(String name, String fieldQuery);
+
     }
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
index 93c01a3..25f1130 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
@@ -22,7 +22,7 @@ import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 
 import java.util.Collection;
 
-public interface PlcSubscriptionResponse extends PlcFieldResponse {
+public interface PlcSubscriptionResponse extends PlcSubscriptionFieldResponse {
 
     @Override
     PlcSubscriptionRequest getRequest();
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
index 1fc024a..8e2b12a 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
@@ -21,10 +21,13 @@ package org.apache.plc4x.java.api.messages;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 public interface PlcUnsubscriptionRequest extends PlcRequest {
 
+    List<PlcSubscriptionHandle> getSubscriptionHandles();
+
     @Override
     CompletableFuture<PlcUnsubscriptionResponse> execute();
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
index ebd789b..9b19038 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
@@ -18,13 +18,8 @@
  */
 package org.apache.plc4x.java.api.messages;
 
-import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.value.PlcValue;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
 import java.util.concurrent.CompletableFuture;
 
 public interface PlcWriteRequest extends PlcFieldRequest {
@@ -34,13 +29,15 @@ public interface PlcWriteRequest extends PlcFieldRequest {
 
     int getNumberOfValues(String name);
 
+    PlcValue getPlcValue(String name);
+
     interface Builder extends PlcRequestBuilder {
 
         @Override
         PlcWriteRequest build();
 
-        <T> PlcWriteRequest.Builder addItem(String name, String fieldQuery, Object... values);
-        <T> PlcWriteRequest.Builder addItem(String name, PlcField fieldQuery, Object... values);
+        PlcWriteRequest.Builder addItem(String name, String fieldQuery, Object... values);
+
     }
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
index 2abbe85..f885564 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
@@ -19,6 +19,18 @@
 
 package org.apache.plc4x.java.api.model;
 
+import java.util.List;
+
+/**
+ * Represents the registration of one consumer for a given subscription handle.
+ * Also provides the means to unsubscribe.
+ */
 public interface PlcConsumerRegistration {
+
+    Integer getConsumerId();
+
+    List<PlcSubscriptionHandle> getSubscriptionHandles();
+
     void unregister();
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/types/FieldType.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
similarity index 68%
rename from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/types/FieldType.java
rename to plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
index 215476a..e05c286 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/types/FieldType.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
@@ -16,32 +16,17 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.spi.types;
-
-public enum FieldType {
-
-    BIT_1,
-    BIT_8,
-    BIT_16,
-    BIT_32,
-    BIT_64,
-    INT_2,
-    INT_4,
-    INT_8,
-    INT_16,
-    INT_32,
-    INT_64,
-    UINT_2,
-    UINT_4,
-    UINT_8,
-    UINT_16,
-    UINT_32,
-    UINT_64,
-    FLOAT_16,
-    FLOAT_32,
-    UFLOAT_16,
-    UFLOAT_32,
-    CHAR,
-    STRING
+package org.apache.plc4x.java.api.model;
+
+import org.apache.plc4x.java.api.types.PlcSubscriptionType;
+
+import java.time.Duration;
+import java.util.Optional;
+
+public interface PlcSubscriptionField extends PlcField {
+
+    PlcSubscriptionType getPlcSubscriptionType();
+
+    Optional<Duration> getDuration();
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
index 7bfdfd5..97426bc 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
@@ -29,10 +29,16 @@ import java.util.function.Consumer;
  * all information needed to pull or unsubscribe any form of subscription.
  * <p>
  * For every subscribed item, a separate {@link PlcSubscriptionHandle} object is
- * returned in order to allow fine granular unsubscriptions.
+ * returned in order to allow fine granular un-subscriptions.
  */
 public interface PlcSubscriptionHandle {
 
+    /**
+     * Registers a given consumer for the events emitted by the current subscription handle.
+     *
+     * @param consumer consumer
+     * @return consumer registration
+     */
     PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer);
 
 }
diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
index 7841b2d..0a98a0b 100644
--- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
+++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
@@ -26,7 +26,7 @@ import org.apache.plc4x.java.abeth.protocol.AbEthProtocolLogic;
 import org.apache.plc4x.java.abeth.readwrite.CIPEncapsulationPacket;
 import org.apache.plc4x.java.abeth.readwrite.io.CIPEncapsulationPacketIO;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/field/AbEthFieldHandler.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/field/AbEthFieldHandler.java
index fc1a827..570dc3e 100644
--- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/field/AbEthFieldHandler.java
+++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/field/AbEthFieldHandler.java
@@ -20,9 +20,9 @@ package org.apache.plc4x.java.abeth.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-public class AbEthFieldHandler extends DefaultPlcFieldHandler {
+public class AbEthFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java
index 1c5b191..d57fcfb 100644
--- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java
+++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java
@@ -31,14 +31,14 @@ import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.PlcINT;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.time.Duration;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
@@ -208,7 +208,7 @@ public class AbEthProtocolLogic extends Plc4xProtocolBase<CIPEncapsulationPacket
         }
 
         // TODO: Double check if it's really a InternalPlcReadRequest ...
-        return new DefaultPlcReadResponse((InternalPlcReadRequest) plcReadRequest, values);
+        return new DefaultPlcReadResponse(plcReadRequest, values);
     }
 
     private PlcResponseCode decodeResponseCode(short status) {
diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
index 9002420..de60b11 100644
--- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
+++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
@@ -33,13 +33,12 @@ import org.apache.plc4x.java.spi.PlcMessageToMessageCodec;
 import org.apache.plc4x.java.spi.events.ConnectEvent;
 import org.apache.plc4x.java.spi.events.ConnectedEvent;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.PlcRequestContainer;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.apache.plc4x.java.spi.values.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -163,7 +162,7 @@ public class Plc4xAbEthProtocol extends PlcMessageToMessageCodec<CIPEncapsulatio
     private PlcResponse decodeReadResponse(
         CIPEncapsulationReadResponse plcReadResponse, PlcRequestContainer requestContainer) {
 
-        InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest();
+        PlcReadRequest plcReadRequest = (PlcReadRequest) requestContainer.getRequest();
 
         Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
         for (String fieldName : plcReadRequest.getFieldNames()) {
diff --git a/plc4j/drivers/ads/pom.xml b/plc4j/drivers/ads/pom.xml
index fa86807..d37eed2 100644
--- a/plc4j/drivers/ads/pom.xml
+++ b/plc4j/drivers/ads/pom.xml
@@ -144,33 +144,8 @@
 
     <dependency>
       <groupId>org.apache.commons</groupId>
-      <artifactId>commons-configuration2</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
-    <dependency>
-      <groupId>com.github.snksoft</groupId>
-      <artifactId>crc</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty-buffer</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty-common</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty-transport</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty-codec</artifactId>
-    </dependency>
 
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
index 8d51021..d4553f2 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
@@ -23,7 +23,7 @@ import org.apache.plc4x.java.ads.field.AdsFieldHandler;
 import org.apache.plc4x.java.ads.protocol.AdsProtocolLogic;
 import org.apache.plc4x.java.ads.readwrite.AmsTCPPacket;
 import org.apache.plc4x.java.ads.readwrite.io.AmsTCPPacketIO;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsField.java
index 6f42d92..a5b2c25 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsField.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsField.java
@@ -20,8 +20,9 @@ package org.apache.plc4x.java.ads.field;
 
 import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
 
-public interface AdsField extends PlcField {
+public interface AdsField extends PlcField, XmlSerializable {
 
     AdsDataType getAdsDataType();
 
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
index b5e47bd..2b85eea 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
@@ -18,23 +18,11 @@
  */
 package org.apache.plc4x.java.ads.field;
 
-import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class AdsFieldHandler extends DefaultPlcFieldHandler {
+public class AdsFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
@@ -45,4 +33,5 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
         }
         throw new PlcInvalidFieldException(fieldQuery);
     }
+
 }
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsField.java
index 20051d7..f405a21 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsField.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsField.java
@@ -20,6 +20,8 @@ package org.apache.plc4x.java.ads.field;
 
 import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Objects;
 import java.util.regex.Matcher;
@@ -144,4 +146,27 @@ public class DirectAdsField implements AdsField {
             ", indexOffset=" + indexOffset +
             '}';
     }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement(getClass().getSimpleName());
+        parent.appendChild(messageElement);
+        Element indexGroupElement = doc.createElement("indexGroup");
+        indexGroupElement.appendChild(doc.createTextNode(Long.toString(getIndexGroup())));
+        messageElement.appendChild(indexGroupElement);
+
+        Element indexOffsetElement = doc.createElement("indexOffset");
+        indexOffsetElement.appendChild(doc.createTextNode(Long.toString(getIndexOffset())));
+        messageElement.appendChild(indexOffsetElement);
+
+        Element numberOfElementsElement = doc.createElement("numberOfElements");
+        numberOfElementsElement.appendChild(doc.createTextNode(Integer.toString(getNumberOfElements())));
+        messageElement.appendChild(numberOfElementsElement);
+
+        Element datatypeElement = doc.createElement("dataType");
+        datatypeElement.appendChild(doc.createTextNode(getPlcDataType()));
+        messageElement.appendChild(datatypeElement);
+    }
+
 }
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
index 6229c66..d18305b 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
@@ -20,6 +20,8 @@ package org.apache.plc4x.java.ads.field;
 
 import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Objects;
 import java.util.regex.Matcher;
@@ -109,4 +111,23 @@ public class SymbolicAdsField implements AdsField {
             "symbolicAddress='" + symbolicAddress + '\'' +
             '}';
     }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement(getClass().getSimpleName());
+        parent.appendChild(messageElement);
+
+        Element symbolicAddressElement = doc.createElement("symbolicAddress");
+        symbolicAddressElement.appendChild(doc.createTextNode(getSymbolicField()));
+        messageElement.appendChild(symbolicAddressElement);
+
+        Element numberOfElementsElement = doc.createElement("numberOfElements");
+        numberOfElementsElement.appendChild(doc.createTextNode(Integer.toString(getNumberOfElements())));
+        messageElement.appendChild(numberOfElementsElement);
+
+        Element datatypeElement = doc.createElement("dataType");
+        datatypeElement.appendChild(doc.createTextNode(getPlcDataType()));
+        messageElement.appendChild(datatypeElement);
+    }
 }
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
index 7f33247..21215cd 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
@@ -44,10 +44,9 @@ import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WriteBuffer;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -285,7 +284,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
                     values.put(fieldName, parsePlcValue(field, readBuffer));
                 }
             }
-            return new DefaultPlcReadResponse((InternalPlcReadRequest) readRequest, values);
+            return new DefaultPlcReadResponse(readRequest, values);
         }
         return null;
     }
@@ -332,7 +331,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         if(directAdsFieldsFuture.isDone()) {
             final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null);
             if(fields != null) {
-                return executeWrite((InternalPlcWriteRequest) writeRequest, fields);
+                return executeWrite(writeRequest, fields);
             } else {
                 final CompletableFuture<PlcWriteResponse> errorFuture = new CompletableFuture<>();
                 errorFuture.completeExceptionally(new PlcException("Error"));
@@ -351,7 +350,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             directAdsFieldsFuture.handle((directAdsFields, throwable) -> {
                 if(directAdsFields != null) {
                     final CompletableFuture<PlcWriteResponse> delayedResponse =
-                        executeWrite((InternalPlcWriteRequest) writeRequest, directAdsFields);
+                        executeWrite(writeRequest, directAdsFields);
                     delayedResponse.handle((plcReadResponse, throwable1) -> {
                         if (plcReadResponse != null) {
                             delayedWrite.complete(plcReadResponse);
@@ -369,7 +368,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         }
     }
 
-    protected CompletableFuture<PlcWriteResponse> executeWrite(InternalPlcWriteRequest writeRequest,
+    protected CompletableFuture<PlcWriteResponse> executeWrite(PlcWriteRequest writeRequest,
                                                              List<DirectAdsField> directAdsFields) {
         // Depending on the number of fields, use a single item request or a sum-request
         if (directAdsFields.size() == 1) {
@@ -382,7 +381,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         }
     }
 
-    protected CompletableFuture<PlcWriteResponse> singleWrite(InternalPlcWriteRequest writeRequest, DirectAdsField directAdsField) {
+    protected CompletableFuture<PlcWriteResponse> singleWrite(PlcWriteRequest writeRequest, DirectAdsField directAdsField) {
         CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
 
         final String fieldName = writeRequest.getFieldNames().iterator().next();
@@ -423,7 +422,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         return future;
     }
 
-    protected CompletableFuture<PlcWriteResponse> multiWrite(InternalPlcWriteRequest writeRequest, List<DirectAdsField> directAdsFields) {
+    protected CompletableFuture<PlcWriteResponse> multiWrite(PlcWriteRequest writeRequest, List<DirectAdsField> directAdsFields) {
         CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
 
         // Calculate the size of all fields together.
@@ -502,7 +501,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             }
         }
 
-        return new DefaultPlcWriteResponse((InternalPlcWriteRequest) writeRequest, responseCodes);
+        return new DefaultPlcWriteResponse(writeRequest, responseCodes);
     }
 
     @Override
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsAbstractPlcConnection.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsAbstractPlcConnection.java
deleted file mode 100644
index ce944d9..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsAbstractPlcConnection.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.connection;
-
-import io.netty.channel.ChannelFuture;
-import org.apache.commons.configuration2.Configuration;
-import org.apache.commons.configuration2.SystemConfiguration;
-import org.apache.plc4x.java.ads.field.AdsFieldHandler;
-import org.apache.plc4x.java.ads.field.DirectAdsField;
-import org.apache.plc4x.java.ads.field.SymbolicAdsField;
-import org.apache.plc4x.java.ads.readwrite.*;
-import org.apache.plc4x.java.ads.readwrite.types.ReturnCode;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.messages.*;
-import org.apache.plc4x.java.spi.connection.ChannelFactory;
-import org.apache.plc4x.java.spi.connection.DefaultNettyPlcConnection;
-import org.apache.plc4x.java.spi.messages.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.concurrent.*;
-
-@Deprecated
-public abstract class AdsAbstractPlcConnection extends DefaultNettyPlcConnection implements PlcReader, PlcWriter, PlcProprietarySender {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(AdsAbstractPlcConnection.class);
-
-    protected static final Configuration CONF = new SystemConfiguration();
-    protected static final long SYMBOL_RESOLVE_TIMEOUT = CONF.getLong("plc4x.adsconnection.symbol.resolve,timeout", 3000);
-
-    protected final AmsNetId targetAmsNetId;
-
-    protected final int targetAmsPort;
-
-    protected final AmsNetId sourceAmsNetId;
-
-    protected final int sourceAmsPort;
-
-    protected final ConcurrentMap<SymbolicAdsField, DirectAdsField> fieldMapping;
-
-    protected AdsAbstractPlcConnection(ChannelFactory channelFactory, AmsNetId targetAmsNetId, int targetAmsPort) {
-        this(channelFactory, targetAmsNetId, targetAmsPort, generateAmsNetId(), generateAMSPort());
-    }
-
-    protected AdsAbstractPlcConnection(ChannelFactory channelFactory, AmsNetId targetAmsNetId, int targetAmsPort, AmsNetId sourceAmsNetId, int sourceAmsPort) {
-        super(true, true, true, new AdsFieldHandler(), null, channelFactory, false, null, null);
-        this.targetAmsNetId = targetAmsNetId;
-        this.targetAmsPort = targetAmsPort;
-        this.sourceAmsNetId = sourceAmsNetId;
-        this.sourceAmsPort = sourceAmsPort;
-        this.fieldMapping = new ConcurrentHashMap<>();
-    }
-
-    @Override
-    public boolean canRead() {
-        return true;
-    }
-
-    @Override
-    public boolean canWrite() {
-        return true;
-    }
-
-    @Override
-    public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
-        mapFields(readRequest);
-        CompletableFuture<InternalPlcReadResponse> readFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcReadRequest) readRequest, readFuture));
-        channelFuture.addListener(future -> {
-            if (!future.isSuccess()) {
-                readFuture.completeExceptionally(future.cause());
-            }
-        });
-        return readFuture
-            .thenApply(PlcReadResponse.class::cast);
-    }
-
-    @Override
-    public PlcReadRequest.Builder readRequestBuilder() {
-        return new DefaultPlcReadRequest.Builder(this, new AdsFieldHandler());
-    }
-
-    @Override
-    public PlcWriteRequest.Builder writeRequestBuilder() {
-        return new DefaultPlcWriteRequest.Builder(this, new AdsFieldHandler());
-    }
-
-    @Override
-    public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
-        mapFields(writeRequest);
-        CompletableFuture<InternalPlcWriteResponse> writeFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcWriteRequest) writeRequest, writeFuture));
-        channelFuture.addListener(future -> {
-            if (!future.isSuccess()) {
-                writeFuture.completeExceptionally(future.cause());
-            }
-        });
-        return writeFuture
-            .thenApply(PlcWriteResponse.class::cast);
-    }
-
-    @Override
-    public <T> CompletableFuture<PlcProprietaryResponse<T>> send(PlcProprietaryRequest proprietaryRequest) {
-        CompletableFuture<InternalPlcProprietaryResponse<T>> sendFuture = new CompletableFuture<>();
-        ChannelFuture channelFuture = channel.writeAndFlush(new PlcRequestContainer<>((InternalPlcProprietaryRequest) proprietaryRequest, sendFuture));
-        channelFuture.addListener(future -> {
-            if (!future.isSuccess()) {
-                sendFuture.completeExceptionally(future.cause());
-            }
-        });
-        return sendFuture
-            .thenApply(PlcProprietaryResponse.class::cast);
-    }
-
-    protected void mapFields(PlcFieldRequest request) {
-        request.getFields().stream()
-            .parallel()
-            .filter(SymbolicAdsField.class::isInstance)
-            .map(SymbolicAdsField.class::cast)
-            .forEach(this::mapFields);
-    }
-
-    protected void mapFields(SymbolicAdsField symbolicAdsField) {
-        // If the map doesn't contain an entry for the given symbolicAdsField,
-        // resolve it and add it to the map.
-        fieldMapping.computeIfAbsent(symbolicAdsField, symbolicAdsFieldInternal -> {
-            LOGGER.debug("Resolving {}", symbolicAdsFieldInternal);
-            AdsReadWriteRequest adsReadWriteRequest = new AdsReadWriteRequest(
-                0xF003L,
-                0L,
-                4L,
-                // TODO: Implement the items ...
-                null,
-                symbolicAdsFieldInternal.getSymbolicField().getBytes()
-            );
-
-            // TODO: This is blocking, should be changed to be async.
-            CompletableFuture<InternalPlcProprietaryResponse<AdsReadWriteResponse>> getHandelFuture = new CompletableFuture<>();
-            channel.writeAndFlush(new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsReadWriteRequest), getHandelFuture));
-            InternalPlcProprietaryResponse<AdsReadWriteResponse> getHandleResponse = getFromFuture(getHandelFuture, SYMBOL_RESOLVE_TIMEOUT);
-            AdsReadWriteResponse response = getHandleResponse.getResponse();
-
-            if (response.getResult() != ReturnCode.OK) {
-                throw new PlcRuntimeException("Non error code received " + response.getResult());
-            }
-
-            ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
-            buffer.order(ByteOrder.LITTLE_ENDIAN);
-            buffer.put(response.getData());
-            Long symbolHandle = buffer.getLong();
-            return DirectAdsField.of(0xF005, symbolHandle, symbolicAdsFieldInternal.getAdsDataType(), symbolicAdsFieldInternal.getNumberOfElements());
-        });
-    }
-
-    protected static AmsNetId generateAmsNetId() {
-        return new AmsNetId((short) 0, (short) 0, (short) 0, (short) 0, (short) 0, (short) 0);
-    }
-
-    protected static int generateAMSPort() {
-        return 0;
-    }
-
-    @Override
-    public void close() throws PlcConnectionException {
-        fieldMapping.values().stream()
-            .parallel()
-            .map(adsField -> {
-                ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
-                buffer.order(ByteOrder.LITTLE_ENDIAN);
-                buffer.putLong(adsField.getIndexGroup());
-                byte[] bytes = buffer.array();
-                return new AdsWriteRequest(
-                    0xF006L,
-                    0L,
-                    bytes
-                );
-            })
-            .map(adsWriteRequest -> new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsWriteRequest), new CompletableFuture<>()))
-            // We don't need a response so we just supply a throw away future.
-            .forEach(channel::write);
-        channel.flush();
-        super.close();
-    }
-
-    /**
-     * Clears the fieldMapping.
-     */
-    public void clearMapping() {
-        fieldMapping.clear();
-    }
-
-    protected <T> T getFromFuture(CompletableFuture<T> future, long timeout) {
-        try {
-            return future.get(timeout, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            LOGGER.warn("Interrupted!", e);
-            Thread.currentThread().interrupt();
-            throw new PlcRuntimeException(e);
-        } catch (ExecutionException | TimeoutException e) {
-            throw new PlcRuntimeException(e);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "AdsAbstractPlcConnection{" +
-            "targetAmsNetId=" + targetAmsNetId +
-            ", targetAmsPort=" + targetAmsPort +
-            ", sourceAmsNetId=" + sourceAmsNetId +
-            ", sourceAmsPort=" + sourceAmsPort +
-            "} " + super.toString();
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsConnectionFactory.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsConnectionFactory.java
deleted file mode 100644
index 6cb8cc6..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsConnectionFactory.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.connection;
-
-import org.apache.plc4x.java.ads.readwrite.AmsNetId;
-
-import java.net.InetAddress;
-import java.util.Objects;
-
-@Deprecated
-public class AdsConnectionFactory {
-
-    public AdsTcpPlcConnection adsTcpPlcConnectionOf(InetAddress address, Integer port, AmsNetId targetAmsNetId, Integer targetAmsPort, AmsNetId sourceAmsNetId, Integer sourceAmsPort) {
-        Objects.requireNonNull(address);
-        Objects.requireNonNull(targetAmsNetId);
-        Objects.requireNonNull(targetAmsPort);
-        if (sourceAmsNetId == null || sourceAmsPort == null) {
-            if (port == null) {
-                return AdsTcpPlcConnection.of(address, targetAmsNetId, targetAmsPort);
-            } else {
-                return AdsTcpPlcConnection.of(address, port, targetAmsNetId, targetAmsPort);
-            }
-        } else {
-            if (port == null) {
-                return AdsTcpPlcConnection.of(address, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
-            } else {
-                return AdsTcpPlcConnection.of(address, port, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
-            }
-        }
-    }
-
-    public AdsSerialPlcConnection adsSerialPlcConnectionOf(String serialPort, AmsNetId targetAmsNetId, Integer targetAmsPort, AmsNetId sourceAmsNetId, Integer sourceAmsPort) {
-        Objects.requireNonNull(serialPort);
-        Objects.requireNonNull(targetAmsNetId);
-        Objects.requireNonNull(targetAmsPort);
-        if (sourceAmsNetId == null || sourceAmsPort == null) {
-            return AdsSerialPlcConnection.of(serialPort, targetAmsNetId, targetAmsPort);
-        } else {
-            return AdsSerialPlcConnection.of(serialPort, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
-        }
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsSerialPlcConnection.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsSerialPlcConnection.java
deleted file mode 100644
index 69db63b..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsSerialPlcConnection.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.connection;
-
-import org.apache.plc4x.java.ads.readwrite.AmsNetId;
-import org.apache.plc4x.java.transport.serial.SerialChannelFactory;
-import org.apache.plc4x.java.transport.serial.SerialSocketAddress;
-
-@Deprecated
-public class AdsSerialPlcConnection extends AdsAbstractPlcConnection {
-
-    private AdsSerialPlcConnection(String serialPort, AmsNetId targetAmsNetId, int targetAmsPort) {
-        this(serialPort, targetAmsNetId, targetAmsPort, generateAmsNetId(), generateAMSPort());
-    }
-
-    private AdsSerialPlcConnection(String serialPort, AmsNetId targetAmsNetId, int targetAmsPort, AmsNetId sourceAmsNetId, int sourceAmsPort) {
-        super(new SerialChannelFactory(new SerialSocketAddress(serialPort)), targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
-    }
-
-    public static AdsSerialPlcConnection of(String serialPort, AmsNetId targetAmsNetId, int targetAmsPort) {
-        return new AdsSerialPlcConnection(serialPort, targetAmsNetId, targetAmsPort);
-    }
-
-    public static AdsSerialPlcConnection of(String serialPort, AmsNetId targetAmsNetId, int targetAmsPort, AmsNetId sourceAmsNetId, int sourceAmsPort) {
-        return new AdsSerialPlcConnection(serialPort, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort);
-    }
-
-    // TODO fix this
-//    @Override
-//    protected ChannelHandler getChannelHandler(CompletableFuture<Void> sessionSetupCompleteFuture) {
-//        return new ChannelInitializer<Channel>() {
-//            @Override
-//            protected void initChannel(Channel channel) {
-//                // Build the protocol stack for communicating with the ads protocol.
-//                ChannelPipeline pipeline = channel.pipeline();
-//                pipeline.addLast(new Payload2SerialProtocol());
-//                pipeline.addLast(new Ads2PayloadProtocol());
-//                pipeline.addLast(new Plc4x2AdsProtocol(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, fieldMapping));
-//                pipeline.addLast(new SingleItemToSingleRequestProtocol(AdsSerialPlcConnection.this, AdsSerialPlcConnection.this, null, timer));
-//            }
-//        };
-//    }
-
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java
deleted file mode 100644
index ae2e221..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.connection;
-
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.plc4x.java.ads.field.AdsFieldHandler;
-import org.apache.plc4x.java.ads.field.DirectAdsField;
-import org.apache.plc4x.java.ads.field.SymbolicAdsField;
-import org.apache.plc4x.java.ads.readwrite.types.ReturnCode;
-import org.apache.plc4x.java.amsads.attic.protocol.Plc4x2AdsProtocol;
-import org.apache.plc4x.java.amsads.attic.protocol.util.LittleEndianDecoder;
-import org.apache.plc4x.java.ads.model.AdsSubscriptionHandle;
-import org.apache.plc4x.java.ads.readwrite.*;
-import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.messages.*;
-import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
-import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.messages.*;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
-import org.apache.plc4x.java.spi.model.InternalPlcConsumerRegistration;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
-import org.apache.plc4x.java.transport.tcp.TcpChannelFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.math.BigInteger;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-@Deprecated
-public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements PlcSubscriber {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(AdsTcpPlcConnection.class);
-
-    private static final int TCP_PORT = 48898;
-
-    private static final long ADD_DEVICE_TIMEOUT = CONF.getLong("plc4x.adsconnection.add.device,timeout", 3000);
-    private static final long DEL_DEVICE_TIMEOUT = CONF.getLong("plc4x.adsconnection.del.device,timeout", 3000);
-
-    private static AtomicInteger localPorts = new AtomicInteger(30000);
-
-    private Map<InternalPlcConsumerRegistration, Consumer<AdsDeviceNotificationRequest>> consumerRegistrations = new HashMap<>();
-
-    private AdsTcpPlcConnection(InetAddress address, AmsNetId targetAmsNetId, int targetint) {
-        this(address, targetAmsNetId, targetint, generateAmsNetId(), generateAmsPort());
-    }
-
-    private AdsTcpPlcConnection(InetAddress address, Integer port, AmsNetId targetAmsNetId, int targetint) {
-        this(address, port, targetAmsNetId, targetint, generateAmsNetId(), generateAmsPort());
-    }
-
-    private AdsTcpPlcConnection(InetAddress address, AmsNetId targetAmsNetId, int targetint, AmsNetId sourceAmsNetId, int sourceint) {
-        this(address, null, targetAmsNetId, targetint, sourceAmsNetId, sourceint);
-    }
-
-    private AdsTcpPlcConnection(InetAddress address, Integer port, AmsNetId targetAmsNetId, int targetint, AmsNetId sourceAmsNetId, int sourceint) {
-        super(new TcpChannelFactory(new InetSocketAddress(address, port)), targetAmsNetId, targetint, sourceAmsNetId, sourceint);
-    }
-
-    public static AdsTcpPlcConnection of(InetAddress address, AmsNetId targetAmsNetId, int targetint) {
-        return new AdsTcpPlcConnection(address, targetAmsNetId, targetint);
-    }
-
-    public static AdsTcpPlcConnection of(InetAddress address, Integer port, AmsNetId targetAmsNetId, int targetint) {
-        return new AdsTcpPlcConnection(address, port, targetAmsNetId, targetint);
-    }
-
-    public static AdsTcpPlcConnection of(InetAddress address, AmsNetId targetAmsNetId, int targetint, AmsNetId sourceAmsNetId, int sourceint) {
-        return new AdsTcpPlcConnection(address, null, targetAmsNetId, targetint, sourceAmsNetId, sourceint);
-    }
-
-    public static AdsTcpPlcConnection of(InetAddress address, Integer port, AmsNetId targetAmsNetId, int targetint, AmsNetId sourceAmsNetId, int sourceint) {
-        return new AdsTcpPlcConnection(address, port, targetAmsNetId, targetint, sourceAmsNetId, sourceint);
-    }
-
-    // TODO fix that
-//    @Override
-//    protected ChannelHandler getChannelHandler(CompletableFuture<Void> sessionSetupCompleteFuture) {
-//        return new ChannelInitializer<Channel>() {
-//            @Override
-//            protected void initChannel(Channel channel) {
-//                // Build the protocol stack for communicating with the ads protocol.
-//                ChannelPipeline pipeline = channel.pipeline();
-//                pipeline.addLast(new Payload2TcpProtocol());
-//                pipeline.addLast(new Ads2PayloadProtocol());
-//                pipeline.addLast(new Plc4x2AdsProtocol(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, fieldMapping));
-//                pipeline.addLast(new SingleItemToSingleRequestProtocol(AdsTcpPlcConnection.this, AdsTcpPlcConnection.this, AdsTcpPlcConnection.this, timer, SingleItemToSingleRequestProtocol.SplitConfig.builder().dontSplitSubscribe().dontSplitUnsubscribe().build(), false));
-//            }
-//        };
-//    }
-
-    protected static AmsNetId generateAmsNetId() {
-        try {
-            String hostAddress = Inet4Address.getLocalHost().getHostAddress();
-            String[] octets = hostAddress.split("\\.");
-            return new AmsNetId(
-                Short.parseShort(octets[3]),
-                Short.parseShort(octets[2]),
-                Short.parseShort(octets[1]),
-                Short.parseShort(octets[0]),
-                (short) 1,
-                (short) 2
-            );
-        } catch (UnknownHostException e) {
-            throw new PlcRuntimeException(e);
-        }
-    }
-
-    protected static int generateAmsPort() {
-        return localPorts.getAndIncrement();
-    }
-
-    @Override
-    public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest plcSubscriptionRequest) {
-        InternalPlcSubscriptionRequest internalPlcSubscriptionRequest = checkInternal(plcSubscriptionRequest, InternalPlcSubscriptionRequest.class);
-        CompletableFuture<PlcSubscriptionResponse> future = new CompletableFuture<>();
-
-        Map responseItems = internalPlcSubscriptionRequest.getSubscriptionPlcFieldMap().entrySet().stream()
-            .map(subscriptionPlcFieldEntry -> {
-                final String plcFieldName = subscriptionPlcFieldEntry.getKey();
-                final SubscriptionPlcField subscriptionPlcField = subscriptionPlcFieldEntry.getValue();
-                final PlcField field = Objects.requireNonNull(subscriptionPlcField.getPlcField());
-
-                final long indexGroup;
-                final long indexOffset;
-                final AdsDataType adsDataType;
-                final 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) {
-                    mapFields((SymbolicAdsField) field);
-                    DirectAdsField directAdsField = fieldMapping.get(field);
-                    if (directAdsField == null) {
-                        throw new PlcRuntimeException("Unresolvable field " + field);
-                    }
-                    indexGroup = directAdsField.getIndexGroup();
-                    indexOffset = directAdsField.getIndexOffset();
-                    adsDataType = directAdsField.getAdsDataType();
-                    numberOfElements = directAdsField.getNumberOfElements();
-                }
-                // If it's no symbolic field, we can continue immediately
-                // without having to do any resolving.
-                else if (field instanceof DirectAdsField) {
-                    DirectAdsField directAdsField = (DirectAdsField) field;
-                    indexGroup = directAdsField.getIndexGroup();
-                    indexOffset = directAdsField.getIndexOffset();
-                    adsDataType = directAdsField.getAdsDataType();
-                    numberOfElements = directAdsField.getNumberOfElements();
-                } else {
-                    throw new IllegalArgumentException("Unsupported field type " + field.getClass());
-                }
-
-                final long transmissionMode;
-                long cycleTime = 4000000;
-                switch (subscriptionPlcField.getPlcSubscriptionType()) {
-                    case CYCLIC:
-                        transmissionMode = 3L;
-                        cycleTime = subscriptionPlcField.getDuration().orElse(Duration.ofSeconds(1)).toMillis();
-                        break;
-                    case CHANGE_OF_STATE:
-                        transmissionMode = 4L;
-                        break;
-                    default:
-                        throw new PlcRuntimeException("Unmapped type " + subscriptionPlcField.getPlcSubscriptionType());
-                }
-
-                // Prepare the subscription request itself.
-                AdsAddDeviceNotificationRequest adsAddDeviceNotificationRequest = new AdsAddDeviceNotificationRequest(
-                    indexGroup,
-                    indexOffset,
-                    adsDataType.getNumBytes() * (long) numberOfElements,
-                    transmissionMode,
-                    cycleTime + 1,
-                    cycleTime
-                );
-
-                // Send the request to the plc and wait for a response
-                // TODO: This is blocking, should be changed to be async.
-                CompletableFuture<InternalPlcProprietaryResponse<AdsAddDeviceNotificationResponse>> addDeviceFuture = new CompletableFuture<>();
-                channel.writeAndFlush(new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsAddDeviceNotificationRequest), addDeviceFuture));
-                InternalPlcProprietaryResponse<AdsAddDeviceNotificationResponse> addDeviceResponse = getFromFuture(addDeviceFuture, ADD_DEVICE_TIMEOUT);
-                AdsAddDeviceNotificationResponse response = addDeviceResponse.getResponse();
-
-                // Abort if we got anything but a successful response.
-                if (response.getResult() != ReturnCode.OK) {
-                    throw new PlcRuntimeException("Error code received " + response.getResult());
-                }
-                PlcSubscriptionHandle adsSubscriptionHandle = new AdsSubscriptionHandle(this, plcFieldName, adsDataType, response.getNotificationHandle());
-                return Pair.of(plcFieldName, new ResponseItem(PlcResponseCode.OK, adsSubscriptionHandle));
-            })
-            .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
-
-        future.complete(new DefaultPlcSubscriptionResponse(internalPlcSubscriptionRequest, responseItems));
-        return future;
-    }
-
-    @Override
-    public CompletableFuture<PlcUnsubscriptionResponse> unsubscribe(PlcUnsubscriptionRequest plcUnsubscriptionRequest) {
-        InternalPlcUnsubscriptionRequest internalPlcUnsubscriptionRequest = checkInternal(plcUnsubscriptionRequest, InternalPlcUnsubscriptionRequest.class);
-        for (InternalPlcSubscriptionHandle internalPlcSubscriptionHandle : internalPlcUnsubscriptionRequest.getInternalPlcSubscriptionHandles()) {
-            if (internalPlcSubscriptionHandle instanceof AdsSubscriptionHandle) {
-                AdsSubscriptionHandle adsSubscriptionHandle = (AdsSubscriptionHandle) internalPlcSubscriptionHandle;
-                AdsDeleteDeviceNotificationRequest adsDeleteDeviceNotificationRequest = new AdsDeleteDeviceNotificationRequest(
-                    adsSubscriptionHandle.getNotificationHandle()
-                );
-                CompletableFuture<InternalPlcProprietaryResponse<AdsDeleteDeviceNotificationResponse>> deleteDeviceFuture =
-                    new CompletableFuture<>();
-                channel.writeAndFlush(new PlcRequestContainer<>(new DefaultPlcProprietaryRequest<>(adsDeleteDeviceNotificationRequest), deleteDeviceFuture));
-
-                InternalPlcProprietaryResponse<AdsDeleteDeviceNotificationResponse> deleteDeviceResponse =
-                    getFromFuture(deleteDeviceFuture, DEL_DEVICE_TIMEOUT);
-                AdsDeleteDeviceNotificationResponse response = deleteDeviceResponse.getResponse();
-                if (response.getResult() != ReturnCode.OK) {
-                    throw new PlcRuntimeException("Non error code received " + response.getResult());
-                }
-            }
-        }
-        CompletableFuture<PlcUnsubscriptionResponse> future = new CompletableFuture<>();
-        future.complete(new DefaultPlcUnsubscriptionResponse(internalPlcUnsubscriptionRequest));
-        return future;
-    }
-
-    @Override
-    public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> handles) {
-        return register(consumer, handles.toArray(new PlcSubscriptionHandle[0]));
-    }
-
-    public InternalPlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, PlcSubscriptionHandle... handles) {
-        Objects.requireNonNull(consumer);
-        Objects.requireNonNull(handles);
-        InternalPlcSubscriptionHandle[] internalPlcSubscriptionHandles = new InternalPlcSubscriptionHandle[handles.length];
-        for (int i = 0; i < handles.length; i++) {
-            internalPlcSubscriptionHandles[i] = checkInternal(handles[i], InternalPlcSubscriptionHandle.class);
-        }
-
-        InternalPlcConsumerRegistration internalPlcConsumerRegistration = new DefaultPlcConsumerRegistration(this, consumer, internalPlcSubscriptionHandles);
-        Map<Long, AdsSubscriptionHandle> notificationHandleAdsSubscriptionHandleMap = Arrays.stream(internalPlcSubscriptionHandles)
-            .map(subscriptionHandle -> checkInternal(subscriptionHandle, AdsSubscriptionHandle.class))
-            .collect(Collectors.toConcurrentMap(AdsSubscriptionHandle::getNotificationHandle, Function.identity()));
-
-        Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer =
-            adsDeviceNotificationRequest -> Arrays.asList(adsDeviceNotificationRequest.getAdsStampHeaders()).forEach(adsStampHeader -> {
-                BigInteger winTime = adsStampHeader.getTimestamp();
-                BigInteger timeMillisSince16010101 = winTime.divide(BigInteger.valueOf(10_000));
-                BigInteger EPOCH_DIFF_IN_MILLIS = BigInteger.valueOf((369L * 365L + 89L) * 86400L * 1000L);
-                BigInteger subtract = timeMillisSince16010101.subtract(EPOCH_DIFF_IN_MILLIS);
-                Instant timeStamp = new Date(subtract.longValue()).toInstant();
-
-                Map<String, ResponseItem<PlcValue>> fields = new HashMap<>();
-                Arrays.asList(adsStampHeader.getAdsNotificationSamples())
-                    .forEach(adsNotificationSample -> {
-                        Long notificationHandle = adsNotificationSample.getNotificationHandle();
-                        byte[] data = adsNotificationSample.getData();
-                        AdsSubscriptionHandle adsSubscriptionHandle = notificationHandleAdsSubscriptionHandleMap.get(notificationHandle);
-                        if (adsSubscriptionHandle == null) {
-                            // TODO: we might want to refactor this so that we don't subscribe to everything in the first place.
-                            // TODO: rather than we add a Consumer with the handle as key
-                            LOGGER.trace("We are not interested in this sample {} with handle {}", adsNotificationSample, notificationHandle);
-                            return;
-                        }
-                        String plcFieldName = adsSubscriptionHandle.getPlcFieldName();
-                        AdsDataType adsDataType = adsSubscriptionHandle.getAdsDataType();
-                        try {
-                            PlcValue baseDefaultPlcValue = LittleEndianDecoder.decodeData(adsDataType, data);
-                            fields.put(plcFieldName, new ResponseItem<>(PlcResponseCode.OK, baseDefaultPlcValue));
-                        } catch (RuntimeException e) {
-                            LOGGER.error("Can't decode {}", data, e);
-                        }
-
-                    });
-                try {
-                    PlcSubscriptionEvent subscriptionEventItem = new DefaultPlcSubscriptionEvent(timeStamp, fields);
-                    consumer.accept(subscriptionEventItem);
-                } catch (RuntimeException e) {
-                    LOGGER.error("Can't dispatch adsStampHeader {}", adsStampHeader, e);
-                }
-            });
-
-        // Store the reference for so it can be uses for later
-        consumerRegistrations.put(internalPlcConsumerRegistration, adsDeviceNotificationRequestConsumer);
-        // register the actual consumer.
-        getChannel().pipeline().get(Plc4x2AdsProtocol.class).addConsumer(adsDeviceNotificationRequestConsumer);
-
-        return internalPlcConsumerRegistration;
-    }
-
-    @Override
-    public void unregister(PlcConsumerRegistration plcConsumerRegistration) {
-        InternalPlcConsumerRegistration internalPlcConsumerRegistration = checkInternal(plcConsumerRegistration, InternalPlcConsumerRegistration.class);
-        Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer = consumerRegistrations.remove(internalPlcConsumerRegistration);
-        if (adsDeviceNotificationRequestConsumer == null) {
-            return;
-        }
-        getChannel().pipeline().get(Plc4x2AdsProtocol.class).removeConsumer(adsDeviceNotificationRequestConsumer);
-    }
-
-    @Override
-    public boolean canSubscribe() {
-        return true;
-    }
-
-    @Override
-    public PlcSubscriptionRequest.Builder subscriptionRequestBuilder() {
-        return new DefaultPlcSubscriptionRequest.Builder(this, new AdsFieldHandler());
-    }
-
-    @Override
-    public PlcUnsubscriptionRequest.Builder unsubscriptionRequestBuilder() {
-        return new DefaultPlcUnsubscriptionRequest.Builder(this);
-    }
-
-    @Override
-    public void close() throws PlcConnectionException {
-        try {
-            consumerRegistrations.values().forEach(getChannel().pipeline().get(Plc4x2AdsProtocol.class)::removeConsumer);
-            List<PlcSubscriptionHandle> collect = consumerRegistrations.keySet().stream()
-                .map(InternalPlcConsumerRegistration::getAssociatedHandles)
-                .flatMap(Collection::stream)
-                .map(PlcSubscriptionHandle.class::cast)
-                .collect(Collectors.toList());
-
-            PlcUnsubscriptionRequest plcUnsubscriptionRequest = new DefaultPlcUnsubscriptionRequest.Builder(this).addHandles(collect).build();
-            unsubscribe(plcUnsubscriptionRequest).get(5, TimeUnit.SECONDS);
-
-            consumerRegistrations.clear();
-        } catch (InterruptedException e) {
-            LOGGER.warn("Exception while closing", e);
-            Thread.currentThread().interrupt();
-        } catch (RuntimeException | ExecutionException | TimeoutException e) {
-            LOGGER.warn("Exception while closing", e);
-        }
-        super.close();
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java
deleted file mode 100644
index f2074ec..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToMessageCodec;
-import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
-import org.apache.plc4x.java.ads.readwrite.AmsPacket;
-import org.apache.plc4x.java.ads.readwrite.io.AmsPacketIO;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-@Deprecated
-public class Ads2PayloadProtocol extends MessageToMessageCodec<ByteBuf, AmsPacket> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(Ads2PayloadProtocol.class);
-
-    private final ConcurrentMap<Long, AmsPacket> requests;
-
-    public Ads2PayloadProtocol() {
-        this.requests = new ConcurrentHashMap<>();
-    }
-
-    /**
-     * Resets this protocol and discard all send requests.
-     */
-    public void reset() {
-        requests.clear();
-    }
-
-    @Override
-    protected void encode(ChannelHandlerContext channelHandlerContext, AmsPacket amsPacket, List<Object> out) throws AdsException {
-        LOGGER.trace("(<--OUT): {}, {}, {}", channelHandlerContext, amsPacket, out);
-        Long invokeId = amsPacket.getInvokeId();
-        if (invokeId != 0L) {
-            requests.put(invokeId, amsPacket);
-        }
-        WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
-        try {
-            AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
-        } catch (ParseException e) {
-            throw new AdsException(invokeId, e);
-        }
-        out.add(writeBuffer.getData());
-    }
-
-    @Override
-    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) throws AdsException {
-        if (byteBuf == Unpooled.EMPTY_BUFFER) {
-            // Cleanup...
-            reset();
-            return;
-        }
-        LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, byteBuf, out);
-
-        byte[] bytes = new byte[byteBuf.readableBytes()];
-        byteBuf.readBytes(bytes);
-        ReadBuffer readBuffer = new ReadBuffer(bytes);
-        while (readBuffer.getPos() < bytes.length) {
-            try {
-                AmsPacket packet = AmsPacketIO.staticParse(readBuffer);
-                out.add(packet);
-            } catch (Exception e) {
-                LOGGER.warn("Error decoding package: " + e.getMessage());
-            }
-        }
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java
deleted file mode 100644
index b988d29..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToMessageCodec;
-import io.netty.util.concurrent.ScheduledFuture;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
-import org.apache.plc4x.java.amsads.attic.protocol.util.DigestUtil;
-import org.apache.plc4x.java.ads.readwrite.AmsPacket;
-import org.apache.plc4x.java.ads.readwrite.AmsSerialFrame;
-import org.apache.plc4x.java.ads.readwrite.AmsTCPPacket;
-import org.apache.plc4x.java.ads.readwrite.io.AmsPacketIO;
-import org.apache.plc4x.java.ads.readwrite.io.AmsSerialFrameIO;
-import org.apache.plc4x.java.ads.readwrite.io.AmsTCPPacketIO;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-@Deprecated
-public class Payload2SerialProtocol extends MessageToMessageCodec<ByteBuf, ByteBuf> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(Payload2SerialProtocol.class);
-
-    private final AtomicInteger fragmentCounter = new AtomicInteger(0);
-
-    private AtomicReference<ScheduledFuture<?>> currentRetryer = new AtomicReference<>();
-
-    @Override
-    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf amsPacket, List<Object> out) throws AdsException {
-        LOGGER.trace("(<--OUT): {}, {}, {}", channelHandlerContext, amsPacket, out);
-
-        byte[] bytes = amsPacket.array();
-        AmsPacket amsPacketSer;
-        try {
-            amsPacketSer = AmsPacketIO.staticParse(new ReadBuffer(bytes, true));
-        } catch (ParseException e) {
-            throw new AdsException(-1L, e);
-        }
-
-
-        AmsSerialFrame amsSerialFrame = new AmsSerialFrame(
-            0x5A01,
-            (byte) 0,
-            (byte) 0,
-            (byte) 0,
-            (byte) amsPacketSer.getLengthInBytes(),
-            amsPacketSer,
-            DigestUtil.calculateCrc16(ArrayUtils.addAll(new byte[]{0x5A, 0x01, 0, 0, 0, (byte) amsPacketSer.getLengthInBytes()}, bytes))
-        );
-
-        WriteBuffer writeBuffer = new WriteBuffer(amsPacketSer.getLengthInBytes(), true);
-        try {
-            AmsSerialFrameIO.staticSerialize(writeBuffer, amsSerialFrame);
-        } catch (ParseException e) {
-            throw new AdsException(amsPacketSer.getInvokeId(), e);
-        }
-        out.add(writeBuffer.getData());
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) {
-        if (byteBuf == Unpooled.EMPTY_BUFFER) {
-            // Cleanup...
-            return;
-        }
-        LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, byteBuf, out);
-        byte[] bytes = new byte[byteBuf.readableBytes()];
-        byteBuf.readBytes(bytes);
-        ReadBuffer readBuffer = new ReadBuffer(bytes);
-        while (readBuffer.getPos() < bytes.length) {
-            try {
-                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
-                AmsPacket amsPacket = amsTCPPacket.getUserdata();
-
-                WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
-                try {
-                    AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
-                } catch (ParseException e) {
-                    throw new AdsException(amsPacket.getInvokeId(), e);
-                }
-                out.add(writeBuffer.getData());
-            } catch (Exception e) {
-                LOGGER.warn("Error decoding package: " + e.getMessage());
-            }
-        }
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java
deleted file mode 100644
index 96341d2..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToMessageCodec;
-import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
-import org.apache.plc4x.java.ads.readwrite.AmsPacket;
-import org.apache.plc4x.java.ads.readwrite.AmsTCPPacket;
-import org.apache.plc4x.java.ads.readwrite.io.AmsPacketIO;
-import org.apache.plc4x.java.ads.readwrite.io.AmsTCPPacketIO;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-
-@Deprecated
-public class Payload2TcpProtocol extends MessageToMessageCodec<ByteBuf, ByteBuf> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(Payload2TcpProtocol.class);
-
-    @Override
-    protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf amsPacket, List<Object> out) throws AdsException {
-        LOGGER.trace("(<--OUT): {}, {}, {}", channelHandlerContext, amsPacket, out);
-
-        byte[] bytes = amsPacket.array();
-        AmsPacket amsPacketSer;
-        try {
-            amsPacketSer = AmsPacketIO.staticParse(new ReadBuffer(bytes, true));
-        } catch (ParseException e) {
-            throw new AdsException(-1L, e);
-        }
-
-        WriteBuffer writeBuffer = new WriteBuffer(amsPacketSer.getLengthInBytes(), true);
-        try {
-            AmsTCPPacketIO.staticSerialize(writeBuffer, new AmsTCPPacket(amsPacketSer));
-        } catch (ParseException e) {
-            throw new AdsException(amsPacketSer.getInvokeId(), e);
-        }
-        out.add(writeBuffer.getData());
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) {
-        if (byteBuf == Unpooled.EMPTY_BUFFER) {
-            // Cleanup...
-            return;
-        }
-        LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, byteBuf, out);
-        byte[] bytes = new byte[byteBuf.readableBytes()];
-        byteBuf.readBytes(bytes);
-        ReadBuffer readBuffer = new ReadBuffer(bytes);
-        while (readBuffer.getPos() < bytes.length) {
-            try {
-                AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
-                AmsPacket amsPacket = amsTCPPacket.getUserdata();
-
-                WriteBuffer writeBuffer = new WriteBuffer(amsPacket.getLengthInBytes(), true);
-                try {
-                    AmsPacketIO.staticSerialize(writeBuffer, amsPacket);
-                } catch (ParseException e) {
-                    throw new AdsException(amsPacket.getInvokeId(), e);
-                }
-                out.add(writeBuffer.getData());
-            } catch (Exception e) {
-                LOGGER.warn("Error decoding package: " + e.getMessage());
-            }
-        }
-    }
-
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java
deleted file mode 100644
index 1baffe8..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol;
-
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToMessageCodec;
-import org.apache.plc4x.java.ads.readwrite.types.ReturnCode;
-import org.apache.plc4x.java.ads.field.AdsField;
-import org.apache.plc4x.java.ads.field.DirectAdsField;
-import org.apache.plc4x.java.ads.field.SymbolicAdsField;
-import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
-import org.apache.plc4x.java.ads.readwrite.*;
-import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
-import org.apache.plc4x.java.ads.readwrite.types.CommandId;
-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.exceptions.PlcProtocolPayloadTooBigException;
-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.api.value.PlcList;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.messages.*;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-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.amsads.attic.protocol.util.LittleEndianDecoder.decodeData;
-
-@Deprecated
-public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(Plc4x2AdsProtocol.class);
-
-    private static final AtomicLong correlationBuilder = new AtomicLong(1);
-
-    private final ConcurrentMap<Long, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> requests;
-
-    private final ConcurrentMap<SymbolicAdsField, DirectAdsField> fieldMapping;
-
-    private List<Consumer<AdsDeviceNotificationRequest>> deviceNotificationListeners;
-
-    private final AmsNetId targetAmsNetId;
-    private final int targetAmsPort;
-    private final AmsNetId sourceAmsNetId;
-    private final int sourceAmsPort;
-
-    public Plc4x2AdsProtocol(AmsNetId targetAmsNetId, int targetAmsPort, AmsNetId sourceAmsNetId, int sourceAmsPort, ConcurrentMap<SymbolicAdsField, DirectAdsField> fieldMapping) {
-        this.targetAmsNetId = targetAmsNetId;
-        this.targetAmsPort = targetAmsPort;
-        this.sourceAmsNetId = sourceAmsNetId;
-        this.sourceAmsPort = sourceAmsPort;
-        this.requests = new ConcurrentHashMap<>();
-        this.fieldMapping = fieldMapping;
-        this.deviceNotificationListeners = new LinkedList<>();
-    }
-
-    @Override
-    protected void encode(ChannelHandlerContext ctx, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws Exception {
-        LOGGER.trace("(<--OUT): {}, {}, {}", ctx, msg, out);
-        PlcRequest request = msg.getRequest();
-        if (request instanceof PlcReadRequest) {
-            encodeReadRequest(msg, out);
-        } else if (request instanceof PlcWriteRequest) {
-            encodeWriteRequest(msg, out);
-        } else if (request instanceof PlcProprietaryRequest) {
-            encodeProprietaryRequest(msg, out);
-        } else {
-            throw new PlcProtocolException("Unknown type " + request.getClass());
-        }
-    }
-
-    @Override
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        LOGGER.trace("(-->ERR): {}", ctx, cause);
-        if (cause instanceof AdsException) {
-            Long invokeId = ((AdsException) cause).getInvokeId();
-            if (invokeId != null) {
-                PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> remove = requests.remove(invokeId);
-                if (remove != null) {
-                    remove.getResponseFuture().completeExceptionally(new PlcIoException(cause));
-                } else {
-                    LOGGER.warn("Unrelated exception received {}", invokeId, cause);
-                }
-            } else {
-                super.exceptionCaught(ctx, cause);
-            }
-        } else if ((cause instanceof IOException) && (cause.getMessage().contains("Connection reset by peer") ||
-            cause.getMessage().contains("Operation timed out"))) {
-            String reason = cause.getMessage().contains("Connection reset by peer") ?
-                "Connection terminated unexpectedly" : "Remote host not responding";
-            if (!requests.isEmpty()) {
-                // If the connection is hung up, all still pending requests can be closed.
-                for (PlcRequestContainer requestContainer : requests.values()) {
-                    requestContainer.getResponseFuture().completeExceptionally(new PlcIoException(reason));
-                }
-                // Clear the list
-                requests.clear();
-            }
-        } else {
-            super.exceptionCaught(ctx, cause);
-        }
-    }
-
-    private void encodeWriteRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcException {
-        InternalPlcWriteRequest writeRequest = (InternalPlcWriteRequest) msg.getRequest();
-        if (writeRequest.getFields().size() != 1) {
-            throw new PlcProtocolException("Only one item supported");
-        }
-        PlcField field = writeRequest.getFields().get(0);
-        if (field instanceof SymbolicAdsField) {
-            DirectAdsField mappedField = fieldMapping.get(field);
-            LOGGER.debug("Replacing {} with {}", field, mappedField);
-            field = mappedField;
-        }
-        if (!(field instanceof DirectAdsField)) {
-            throw new PlcProtocolException("PlcField not of type DirectAdsField: " + field.getClass());
-        }
-        DirectAdsField directAdsField = (DirectAdsField) field;
-        long invokeId = correlationBuilder.incrementAndGet();
-        long indexGroup = directAdsField.getIndexGroup();
-        long indexOffset = directAdsField.getIndexOffset();
-
-        PlcValue plcValue = writeRequest.getPlcValues().get(0);
-        Object[] plcValues;
-        if(plcValue instanceof PlcList) {
-            PlcList plcList = (PlcList) plcValue;
-            plcValues = plcList.getList().toArray(new Object[0]);
-        } else {
-            plcValues = new Object[1];
-            plcValues[0] = plcValue.getObject();
-        }
-
-        byte[] bytes = null;//encodeData(directAdsField.getAdsDataType(), plcValues);
-        int bytesToBeWritten = bytes.length;
-        int maxTheoreticalSize = directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements();
-        if (bytesToBeWritten > maxTheoreticalSize) {
-            LOGGER.debug("Requested AdsDatatype {} is exceeded by number of bytes {}. Limit {}.", directAdsField.getAdsDataType(), bytesToBeWritten, maxTheoreticalSize);
-            throw new PlcProtocolPayloadTooBigException("ADS", maxTheoreticalSize, bytesToBeWritten, plcValues);
-        }
-        AdsWriteRequest data = new AdsWriteRequest(indexGroup, indexOffset, bytes);
-        AmsPacket amsPacket = new AmsPacket(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, CommandId.ADS_WRITE, new State(false, false, false, false, false, false, true, false, false), 0, invokeId, data);
-        LOGGER.debug("encoded write request {}", amsPacket);
-        out.add(amsPacket);
-        requests.put(invokeId, msg);
-    }
-
-    private void encodeReadRequest(PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> msg, List<Object> out) throws PlcException {
-        PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest();
-
-        if (readRequest.getFields().size() != 1) {
-            throw new PlcProtocolException("Only one item supported");
-        }
-        PlcField field = readRequest.getFields().get(0);
-        if (field instanceof SymbolicAdsField) {
-            DirectAdsField mappedField = fieldMapping.get(field);
-            if (mappedField == null) {
-                throw new PlcProtocolException("No field mapping for " + field);
-            }
-            LOGGER.debug("Replacing {} with {}", field, mappedField);
-            field = mappedField;
-        }
-        if (!(field instanceof DirectAdsField)) {
-            throw new PlcProtocolException("PlcField not of type DirectAdsField: " + field.getClass());
-        }
-        DirectAdsField directAdsField = (DirectAdsField) field;
-        long invokeId = correlationBuilder.incrementAndGet();
-        long indexGroup = directAdsField.getIndexGroup();
-        long indexOffset = directAdsField.getIndexOffset();
-        AdsDataType adsDataType = directAdsField.getAdsDataType();
-        int numberOfElements = directAdsField.getNumberOfElements();
-        int readLength = adsDataType.getNumBytes() * numberOfElements;
-        AdsReadWriteRequest data = new AdsReadWriteRequest(indexGroup, indexOffset, readLength, null, null);
-        AmsPacket amsPacket = new AmsPacket(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, CommandId.ADS_READ, new State(false, false, false, false, false, false, true, false, false), 0, invokeId, data);
-        LOGGER.debug("encoded read request {}", amsPacket);
-        out.add(amsPacket);
-        requests.put(invokeId, msg);
-    }
-
-    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());
-        }
-        AmsPacket amsPacket = (AmsPacket) plcProprietaryRequest.getProprietaryRequest();
-        LOGGER.debug("encoded proprietary request {}", amsPacket);
-        out.add(amsPacket);
-        requests.put(amsPacket.getInvokeId(), msg);
-    }
-
-    @Override
-    protected void decode(ChannelHandlerContext channelHandlerContext, AmsPacket amsPacket, List<Object> out) throws Exception {
-        LOGGER.trace("(-->IN): {}, {}, {}", channelHandlerContext, amsPacket, out);
-        AdsData data = amsPacket.getData();
-        if (data instanceof AdsDeviceNotificationRequest) {
-            LOGGER.debug("Received notification {}", amsPacket);
-            handleAdsDeviceNotificationRequest((AdsDeviceNotificationRequest) data);
-            return;
-        }
-        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> plcRequestContainer = requests.remove(amsPacket.getInvokeId());
-        if (plcRequestContainer == null) {
-            LOGGER.info("Unmapped packet received {}", amsPacket);
-            return;
-        }
-        PlcRequest request = plcRequestContainer.getRequest();
-        final InternalPlcResponse response;
-
-        // Handle the response to a read request.
-        if (request instanceof PlcReadRequest) {
-            if (data instanceof AdsReadResponse) {
-                response = decodeReadResponse((AdsReadResponse) data, plcRequestContainer);
-            } else {
-                throw new PlcProtocolException("Wrong type correlated " + amsPacket);
-            }
-        } else if (request instanceof PlcWriteRequest) {
-            if (data instanceof AdsWriteResponse) {
-                response = decodeWriteResponse((AdsWriteResponse) data, plcRequestContainer);
-            } else {
-                throw new PlcProtocolException("Wrong type correlated " + amsPacket);
-            }
-        } else if (request instanceof PlcProprietaryRequest) {
-            response = decodeProprietaryResponse(amsPacket, plcRequestContainer);
-        } else {
-            response = null;
-        }
-        LOGGER.debug("Plc4x response {}", response);
-
-        // Confirm the response being handled.
-        if (response != null) {
-            plcRequestContainer.getResponseFuture().complete(response);
-        }
-    }
-
-    private void handleAdsDeviceNotificationRequest(AdsDeviceNotificationRequest adsDeviceNotificationRequest) {
-        for (Consumer<AdsDeviceNotificationRequest> deviceNotificationListener : deviceNotificationListeners) {
-            try {
-                deviceNotificationListener.accept(adsDeviceNotificationRequest);
-            } catch (RuntimeException e) {
-                LOGGER.error("Exception received from {} while handling {}", deviceNotificationListener, adsDeviceNotificationRequest, e);
-            }
-        }
-    }
-
-    public boolean addConsumer(Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer) {
-        return deviceNotificationListeners.add(adsDeviceNotificationRequestConsumer);
-    }
-
-    public boolean removeConsumer(Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer) {
-        return deviceNotificationListeners.remove(adsDeviceNotificationRequestConsumer);
-    }
-
-
-    @SuppressWarnings("unchecked")
-    private InternalPlcResponse decodeWriteResponse(AdsWriteResponse responseMessage, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> requestContainer) {
-        InternalPlcWriteRequest plcWriteRequest = (InternalPlcWriteRequest) requestContainer.getRequest();
-        PlcResponseCode responseCode = decodeResponseCode(responseMessage.getResult());
-
-        // 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,
-                ignore -> responseCode
-            ));
-        return new DefaultPlcWriteResponse(plcWriteRequest, responseItems);
-    }
-
-    @SuppressWarnings("unchecked")
-    private InternalPlcResponse decodeReadResponse(AdsReadResponse responseMessage, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> requestContainer) {
-        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();
-        PlcValue plcValue = decodeData(field.getAdsDataType(), bytes);
-
-        // TODO: does every item has the same ads response or is this whole aggregation broken?
-        Map<String, ResponseItem<PlcValue>> responseItems = plcReadRequest.getFieldNames()
-            .stream()
-            .collect(Collectors.toMap(
-                fieldName -> fieldName,
-                ignore -> new ResponseItem(responseCode, plcValue)
-            ));
-
-        return new DefaultPlcReadResponse(plcReadRequest, responseItems);
-    }
-
-    @SuppressWarnings("unchecked")
-    private InternalPlcResponse decodeProprietaryResponse(AmsPacket amsPacket, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> plcRequestContainer) {
-        return new DefaultPlcProprietaryResponse<>((InternalPlcProprietaryRequest) plcRequestContainer.getRequest(), amsPacket);
-    }
-
-    private PlcResponseCode decodeResponseCode(ReturnCode result) {
-        if (result == ReturnCode.OK) {
-            return PlcResponseCode.OK;
-        } else if (result == ReturnCode.TARGET_HOST_NOT_FOUND) {
-            return PlcResponseCode.INVALID_ADDRESS;
-        } else {
-            return PlcResponseCode.INTERNAL_ERROR;
-        }
-    }
-
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java
deleted file mode 100644
index 249ca9f..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol.exception;
-
-import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-
-public class AdsException extends PlcProtocolException {
-    private final Long invokeId;
-
-    public AdsException(Long invokeId, String message) {
-        super(message);
-        this.invokeId = invokeId;
-    }
-
-    public AdsException(Long invokeId, String message, Throwable cause) {
-        super(message, cause);
-        this.invokeId = invokeId;
-    }
-
-    public AdsException(Long invokeId, Throwable cause) {
-        super(cause);
-        this.invokeId = invokeId;
-    }
-
-    public AdsException(Long invokeId, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-        this.invokeId = invokeId;
-    }
-
-    public Long getInvokeId() {
-        return invokeId;
-    }
-
-    @Override
-    public String toString() {
-        return "AdsException{" +
-            "invokeId=" + invokeId +
-            "} " + super.toString();
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java
deleted file mode 100644
index d81bece..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-
-package org.apache.plc4x.java.amsads.attic.protocol.exception;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-
-public class AdsProtocolOverflowException extends PlcRuntimeException {
-    public AdsProtocolOverflowException(Class<?> clazz, long length) {
-        super("Overflow in datatype " + clazz + " length: " + length);
-    }
-
-    public AdsProtocolOverflowException(String constantName, long expectedLength, long actualLength) {
-        super("Overflow of " + constantName + ": " + expectedLength + ". Actual " + actualLength + "bytes.");
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java
deleted file mode 100644
index 753b9ee..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol.util;
-
-import com.github.snksoft.crc.CRC;
-
-public class DigestUtil {
-
-    public static final CRC.Parameters CRC16 = CRC.Parameters.CRC16;
-
-    public static final CRC.Parameters CRC16_ADS = new CRC.Parameters(
-        CRC16.getWidth(),
-        CRC16.getPolynomial(),
-        0xFFFF,
-        CRC16.isReflectIn(),
-        CRC16.isReflectOut(),
-        CRC16.getFinalXor());
-
-    private static CRC crc = new CRC(CRC16_ADS);
-
-    private DigestUtil() {
-        // Utility class
-    }
-
-    public static int calculateCrc16(byte[] bytes) {
-        short finalCrc = (short) crc.calculateCRC(bytes);
-        return Short.toUnsignedInt(Short.reverseBytes(finalCrc));
-    }
-
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java
deleted file mode 100644
index 6491c97..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol.util;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
-import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
-import org.apache.plc4x.java.api.value.*;
-
-import java.io.ByteArrayOutputStream;
-import java.math.BigInteger;
-import java.util.LinkedList;
-
-// TODO: we might user ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).putInt(port).asArray() etc
-public class LittleEndianDecoder {
-
-    private LittleEndianDecoder() {
-        // Utility class
-    }
-
-    @SuppressWarnings("unchecked")
-    public static PlcValue 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);
-                }
-                if(values.size() == 1) {
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Boolean[values.size()]));
-                }
-            }
-            case BIT8: {
-                LinkedList<Boolean> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readUnsignedByte();
-                    values.offer(aByte != 0);
-                }
-                if(values.size() == 1) {
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Boolean[values.size()]));
-                }
-            }
-            case BITARR8: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readUnsignedByte();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case BITARR16: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int aLong = wrappedBuffer.readUnsignedShortLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case BITARR32: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aLong = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case INT8: {
-                LinkedList<Byte> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    byte aLong = wrappedBuffer.readByte();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcSINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Byte[values.size()]));
-                }
-            }
-            case INT16: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aLong = wrappedBuffer.readShortLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case INT32: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int intLE = wrappedBuffer.readIntLE();
-                    values.offer(intLE);
-                }
-                if(values.size() == 1) {
-                    return new PlcDINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case INT64: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long longLE = wrappedBuffer.readLongLE();
-                    values.offer(longLE);
-                }
-                if(values.size() == 1) {
-                    return new PlcLINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case UINT8: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aLong = wrappedBuffer.readUnsignedByte();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcUSINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case UINT16: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int aLong = wrappedBuffer.readUnsignedShortLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcUINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case UINT32: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aLong = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcUDINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case ULINT:
-            case UINT64: {
-                LinkedList<BigInteger> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    byte[] bytes = new byte[8];
-                    wrappedBuffer.readBytes(bytes);
-                    ArrayUtils.reverse(bytes);
-                    BigInteger bigInteger = new BigInteger(ArrayUtils.insert(0, bytes, (byte) 0x0));
-                    values.offer(bigInteger);
-                }
-                if(values.size() == 1) {
-                    return new PlcULINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new BigInteger[values.size()]));
-                }
-            }
-            case FLOAT: {
-                LinkedList<Float> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    // FIXME: Commented out till we are able to update to the latest netty version.
-                    float aLong = wrappedBuffer.readFloat();
-                    //float aLong = wrappedBuffer.readFloatLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcREAL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Float[values.size()]));
-                }
-            }
-            case DOUBLE: {
-                LinkedList<Double> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    // FIXME: Commented out till we are able to update to the latest netty version.
-                    double aLong = wrappedBuffer.readDouble();
-                    //double aLong = wrappedBuffer.readDoubleLE();
-                    values.offer(aLong);
-                }
-                if(values.size() == 1) {
-                    return new PlcLREAL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Double[values.size()]));
-                }
-            }
-            case BOOL: {
-                LinkedList<Boolean> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readUnsignedByte();
-                    values.offer(aByte != 0);
-                }
-                if(values.size() == 1) {
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Boolean[values.size()]));
-                }
-            }
-            case BYTE: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readUnsignedByte();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case WORD: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int aByte = wrappedBuffer.readUnsignedShortLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case DWORD: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    // TODO: Double-Check this ...
-                    return new PlcBOOL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case SINT: {
-                LinkedList<Byte> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    byte aByte = wrappedBuffer.readByte();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcSINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Byte[values.size()]));
-                }
-            }
-            case USINT: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readUnsignedByte();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcUSINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case INT: {
-                LinkedList<Short> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    short aByte = wrappedBuffer.readShortLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Short[values.size()]));
-                }
-            }
-            case UINT: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int aByte = wrappedBuffer.readUnsignedShortLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcUINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case DINT: {
-                LinkedList<Integer> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    int aByte = wrappedBuffer.readIntLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcDINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Integer[values.size()]));
-                }
-            }
-            case UDINT: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcUDINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case LINT: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readLongLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcLINT(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Long[values.size()]));
-                }
-            }
-            case REAL: {
-                LinkedList<Float> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    // FIXME: Commented out till we are able to update to the latest netty version.
-                    float aByte = wrappedBuffer.readFloat();
-                    //float aByte = wrappedBuffer.readFloatLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcREAL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Float[values.size()]));
-                }
-            }
-            case LREAL: {
-                LinkedList<Double> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    // FIXME: Commented out till we are able to update to the latest netty version.
-                    double aByte = wrappedBuffer.readDouble();
-                    //double aByte = wrappedBuffer.readDoubleLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcLREAL(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new Double[values.size()]));
-                }
-            }
-            case STRING: {
-                LinkedList<String> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    ByteArrayOutputStream os = new ByteArrayOutputStream();
-                    byte aByte;
-                    while ((aByte = wrappedBuffer.readByte()) != 0x0) {
-                        os.write(aByte);
-                    }
-                    values.offer(new String(os.toByteArray()));
-                }
-                if(values.size() == 1) {
-                    return new PlcSTRING(values.get(0));
-                } else {
-                    return IEC61131ValueHandler.newPlcValue(values.toArray(new String[values.size()]));
-                }
-            }
-/*            case TIME: {
-                LinkedList<Long> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(aByte);
-                }
-                if(values.size() == 1) {
-                    return new PlcLong(values.get(0));
-                } else {
-                    return new PlcList(values);
-                }
-            }
-            case TIME_OF_DAY: {
-                LinkedList<LocalTime> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    values.offer(LocalTime.ofNanoOfDay(TimeUnit.MILLISECONDS.toNanos(aByte)));
-                }
-                if(values.size() == 1) {
-                    return new PlcTime(values.get(0));
-                } else {
-                    return new PlcList(values);
-                }
-            }
-            case DATE: {
-                LinkedList<LocalDate> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    // TODO: where to get the zone offset from
-                    LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(aByte, 0, ZoneOffset.UTC);
-                    values.offer(localDateTime.toLocalDate());
-                }
-                if(values.size() == 1) {
-                    return new PlcDate(values.get(0));
-                } else {
-                    return new PlcList(values);
-                }
-            }
-            case DATE_AND_TIME: {
-                LinkedList<LocalDateTime> values = new LinkedList<>();
-                while (wrappedBuffer.isReadable()) {
-                    long aByte = wrappedBuffer.readUnsignedIntLE();
-                    // TODO: where to get the zone offset from
-                    LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(aByte, 0, ZoneOffset.UTC);
-                    values.offer(localDateTime);
-                }
-                if(values.size() == 1) {
-                    return new PlcDateTime(values.get(0));
-                } else {
-                    return new PlcList(values);
-                }
-            }
-            case ARRAY: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case POINTER: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case ENUM: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case STRUCT: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case ALIAS: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case SUB_RANGE_DATA_TYPE: {
-                throw new NotImplementedException("not implemented yet " + adsDataType);
-            }
-            case UNKNOWN:*/
-            default:
-                throw new PlcUnsupportedDataTypeException("Unsupported adsDataType " + adsDataType);
-        }
-    }
-
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java
deleted file mode 100644
index be8cc00..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol.util;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.ads.readwrite.types.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;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.charset.Charset;
-import java.time.*;
-import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-import java.util.stream.Stream;
-
-// TODO: we might user ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).putInt(port).asArray() etc
-public class LittleEndianEncoder {
-
-    private LittleEndianEncoder() {
-        // Utility class
-    }
-
-    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(adsDataType, Arrays.stream(values).map(Boolean.class::cast));
-        } else if (valueType == Byte.class) {
-            result = encodeByte(adsDataType, Arrays.stream(values).map(Byte.class::cast));
-        } else if (valueType == Short.class) {
-            result = encodeShort(adsDataType, Arrays.stream(values).map(Short.class::cast));
-        } else if (valueType == Integer.class) {
-            result = encodeInteger(adsDataType, Arrays.stream(values).map(Integer.class::cast));
-        } else if (valueType == Long.class) {
-            result = encodeLong(adsDataType, Arrays.stream(values).map(Long.class::cast));
-        } else if (valueType == BigInteger.class) {
-            result = encodeBigInteger(adsDataType, Arrays.stream(values).map(BigInteger.class::cast));
-        } else if (valueType == LocalTime.class) {
-            result = encodeLocalTime(adsDataType, Arrays.stream(values).map(LocalTime.class::cast));
-        } else if (valueType == LocalDate.class) {
-            result = encodeLocalDate(adsDataType, Arrays.stream(values).map(LocalDate.class::cast));
-        } else if (valueType == LocalDateTime.class) {
-            result = encodeLocalDateTime(adsDataType, Arrays.stream(values).map(LocalDateTime.class::cast));
-        } else if (valueType == Float.class) {
-            result = encodeFloat(adsDataType, Arrays.stream(values).map(Float.class::cast));
-        } else if (valueType == Double.class) {
-            result = encodeDouble(adsDataType, Arrays.stream(values).map(Double.class::cast));
-        } else if (valueType == String.class) {
-            result = encodeString(adsDataType, Arrays.stream(values).map(String.class::cast));
-        } else if (valueType == byte[].class) {
-            result = encodeByteArray(adsDataType, Arrays.stream(values).map(byte[].class::cast));
-        } else if (valueType == Byte[].class) {
-            result = encodeBigByteArray(adsDataType, Arrays.stream(values).map(Byte[].class::cast));
-        } else {
-            throw new PlcUnsupportedDataTypeException(valueType);
-        }
-
-        // TODO: maybe we can replace this by a smarter flatmap
-        try {
-            return result.collect(
-                ByteArrayOutputStream::new,
-                (bos, byteValue) -> {
-                    try {
-                        bos.write(byteValue);
-                    } catch (IOException e) {
-                        throw new PlcRuntimeException(e);
-                    }
-                },
-                (a, b) -> {
-                }).toByteArray();
-        } catch (PlcRuntimeException e) {
-            throw new PlcProtocolException("Error encoding data", e);
-        }
-    }
-
-    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()))
-            // 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));
-    }
-
-    private static Stream<byte[]> encodeByteArray(AdsDataType adsDataType, Stream<byte[]> byteArrayStream) {
-        // TODO: add boundchecks and add optional extension
-        return byteArrayStream
-            .peek(bytes -> {
-                if (bytes.length > adsDataType.getNumBytes()) {
-                    throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getNumBytes(), 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)
-            .peek(bytes -> {
-                if (bytes.length > adsDataType.getNumBytes()) {
-                    throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getNumBytes(), bytes.length, bytes));
-                }
-            });
-    }
-
-    private static Stream<byte[]> encodeFloat(AdsDataType adsDataType, Stream<Float> floatStream) {
-        return floatStream
-            .peek(value -> checkBound(adsDataType, value))
-            // TODO: check how ads expects this data
-            .map(Float::floatToIntBits)
-            .map(intValue -> new byte[]{
-                (byte) (intValue & 0x000000ff),
-                (byte) ((intValue & 0x0000ff00) >> 8),
-                (byte) ((intValue & 0x00ff0000) >> 16),
-                (byte) ((intValue & 0xff000000) >> 24),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeDouble(AdsDataType adsDataType, Stream<Double> doubleStream) {
-        return doubleStream
-            .peek(value -> checkBound(adsDataType, value))
-            // TODO: check how ads expects this data
-            .map(Double::doubleToLongBits)
-            .map(longValue -> new byte[]{
-                (byte) (longValue & 0x00000000_000000ffL),
-                (byte) ((longValue & 0x00000000_0000ff00L) >> 8),
-                (byte) ((longValue & 0x00000000_00ff0000L) >> 16),
-                (byte) ((longValue & 0x00000000_ff000000L) >> 24),
-                (byte) ((longValue & 0x000000ff_00000000L) >> 32),
-                (byte) ((longValue & 0x0000ff00_00000000L) >> 40),
-                (byte) ((longValue & 0x00ff0000_00000000L) >> 48),
-                (byte) ((longValue & 0xff000000_00000000L) >> 56),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeInteger(AdsDataType adsDataType, Stream<Integer> integerStream) {
-        return integerStream
-            .peek(value -> checkBound(adsDataType, value))
-            .map(intValue -> new byte[]{
-                (byte) (intValue & 0x000000ff),
-                (byte) ((intValue & 0x0000ff00) >> 8),
-                (byte) ((intValue & 0x00ff0000) >> 16),
-                (byte) ((intValue & 0xff000000) >> 24),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    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),
-                (byte) ((longValue & 0x00000000_0000ff00L) >> 8),
-                (byte) ((longValue & 0x00000000_00ff0000L) >> 16),
-                (byte) ((longValue & 0x00000000_ff000000L) >> 24),
-                (byte) ((longValue & 0x000000ff_00000000L) >> 32),
-                (byte) ((longValue & 0x0000ff00_00000000L) >> 40),
-                (byte) ((longValue & 0x00ff0000_00000000L) >> 48),
-                (byte) ((longValue & 0xff000000_00000000L) >> 56),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    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();
-                if (bytes.length > 1 && bytes[0] == 0x0) {
-                    byte[] subArray = Arrays.copyOf(ArrayUtils.subarray(bytes, 1, bytes.length), adsDataType.getNumBytes());
-                    ArrayUtils.reverse(subArray);
-                    return subArray;
-                } else {
-                    ArrayUtils.reverse(Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-                    return bytes;
-                }
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeLocalTime(AdsDataType adsDataType, Stream<LocalTime> localTimeStream) {
-        return localTimeStream
-            .map(localTime -> ChronoUnit.MILLIS.between(LocalTime.of(0, 0), localTime))
-            .peek(value -> checkBound(adsDataType, value))
-            .map(Long::intValue)
-            .map(time -> new byte[]{
-                (byte) (time & 0x00000000_000000ffL),
-                (byte) ((time & 0x00000000_0000ff00L) >> 8),
-                (byte) ((time & 0x00000000_00ff0000L) >> 16),
-                (byte) ((time & 0x00000000_ff000000L) >> 24),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeLocalDate(AdsDataType adsDataType, Stream<LocalDate> localDateStream) {
-        return localDateStream
-            // TODO: fixme: which offset should we use?
-            .map(localDate -> localDate.atTime(0, 0).toInstant(ZoneOffset.UTC))
-            .map(Instant::getEpochSecond)
-            .peek(value -> checkBound(adsDataType, value))
-            .map(Long::intValue)
-            .map(time -> new byte[]{
-                (byte) (time & 0x00000000_000000ffL),
-                (byte) ((time & 0x00000000_0000ff00L) >> 8),
-                (byte) ((time & 0x00000000_00ff0000L) >> 16),
-                (byte) ((time & 0x00000000_ff000000L) >> 24),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeLocalDateTime(AdsDataType adsDataType, Stream<LocalDateTime> localDateTimeStream) {
-        return localDateTimeStream
-            // TODO: fixme: which offset should we use?
-            .map(localDateTime -> localDateTime.toInstant(ZoneOffset.UTC))
-            .map(Instant::getEpochSecond)
-            .peek(value -> checkBound(adsDataType, value))
-            .map(time -> new byte[]{
-                (byte) (time & 0x00000000_000000ffL),
-                (byte) ((time & 0x00000000_0000ff00L) >> 8),
-                (byte) ((time & 0x00000000_00ff0000L) >> 16),
-                (byte) ((time & 0x00000000_ff000000L) >> 24),
-
-                (byte) ((time & 0x000000ff_00000000L) >> 32),
-                (byte) ((time & 0x0000ff00_00000000L) >> 40),
-                (byte) ((time & 0x00ff0000_00000000L) >> 48),
-                (byte) ((time & 0xff000000_00000000L) >> 56),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-
-    private static Stream<byte[]> encodeShort(AdsDataType adsDataType, Stream<Short> shortStream) {
-        return shortStream
-            .peek(value -> checkBound(adsDataType, value))
-            .map(shortValue -> new byte[]{
-                (byte) (shortValue & 0x00ff),
-                (byte) ((shortValue & 0xff00) >> 8),
-            })
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeByte(AdsDataType adsDataType, Stream<Byte> byteStream) {
-        return byteStream
-            .peek(value -> checkBound(adsDataType, value))
-            .map(aByte -> new byte[]{aByte})
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static Stream<byte[]> encodeBoolean(AdsDataType adsDataType, Stream<Boolean> booleanStream) {
-        return booleanStream
-            .map(booleanValue -> new byte[]{booleanValue ? (byte) 0x01 : (byte) 0x00})
-            .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
-    }
-
-    private static void checkBound(AdsDataType adsDataType, double other) {
-        /*if (!adsDataType.withinBounds(other)) {
-            throw new PlcRuntimeException(other + " not within bounds of " + adsDataType);
-        }*/
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java
deleted file mode 100644
index 79de06c..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.protocol.util;
-
-import io.netty.channel.ChannelDuplexHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelPromise;
-import io.netty.util.concurrent.ScheduledFuture;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.SocketAddress;
-import java.util.ArrayDeque;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Inspired by {@code ChannelTrafficShapingHandler} this limiter ensures only one message is sent at a time.
- */
-public class SingleMessageRateLimiter extends ChannelDuplexHandler {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(SingleMessageRateLimiter.class);
-
-    private final ArrayDeque<ToSend> messagesQueue = new ArrayDeque<>();
-
-    private AtomicBoolean messageOnTheWay = new AtomicBoolean(false);
-
-    private ScheduledFuture<?> sender;
-
-    @Override
-    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
-        LOGGER.debug("bind({}, {}, {})", ctx, localAddress, promise);
-        super.bind(ctx, localAddress, promise);
-    }
-
-    @Override
-    public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
-        LOGGER.debug("deregister({}, {})", ctx, promise);
-        super.deregister(ctx, promise);
-    }
-
-    @Override
-    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
-        LOGGER.debug("connect({}, {}, {}, {})", ctx, remoteAddress, localAddress, promise);
-        sender = ctx.executor().scheduleAtFixedRate(() -> {
-            LOGGER.trace("Woke up and doing work messageOnTheWay:{}, messageQueue:{}", messageOnTheWay, messagesQueue);
-            if (!messagesQueue.isEmpty() && messageOnTheWay.compareAndSet(false, true)) {
-                ToSend pop = messagesQueue.pop();
-                LOGGER.debug("Sending {}", pop);
-                pop.channelHandlerContext.writeAndFlush(pop.objectToSend, pop.promise);
-                LOGGER.debug("Send {}", pop);
-            }
-        }, 100, 10, TimeUnit.MILLISECONDS);
-        super.connect(ctx, remoteAddress, localAddress, promise);
-    }
-
-    @Override
-    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
-        LOGGER.debug("disconnect({}, {})", ctx, promise);
-        sender.cancel(false);
-        super.disconnect(ctx, promise);
-    }
-
-    @Override
-    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
-        LOGGER.trace("(<--OUT): {}, {}, {}", ctx, msg, promise);
-        if (messageOnTheWay.compareAndSet(false, true)) {
-            ctx.write(msg, promise);
-        } else {
-            messagesQueue.add(new ToSend(ctx, msg, promise));
-        }
-    }
-
-    @Override
-    public void read(ChannelHandlerContext ctx) throws Exception {
-        LOGGER.trace("(-->In): {}", ctx);
-        messageOnTheWay.set(false);
-        super.read(ctx);
-    }
-
-    @Override
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        LOGGER.trace("(-->ERR): {}", ctx, cause);
-        messageOnTheWay.set(false);
-        super.exceptionCaught(ctx, cause);
-    }
-
-    private static final class ToSend {
-        final ChannelHandlerContext channelHandlerContext;
-        final Object objectToSend;
-        final ChannelPromise promise;
-
-        private ToSend(ChannelHandlerContext channelHandlerContext, Object objectToSend, ChannelPromise promise) {
-            this.channelHandlerContext = channelHandlerContext;
-            this.objectToSend = objectToSend;
-            this.promise = promise;
-        }
-
-        @Override
-        public String toString() {
-            return "ToSend{" +
-                "channelHandlerContext=" + channelHandlerContext +
-                ", objectToSend=" + objectToSend +
-                ", promise=" + promise +
-                '}';
-        }
-    }
-}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java
deleted file mode 100644
index 8b2a99e..0000000
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-package org.apache.plc4x.java.amsads.attic.types;
-
-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;
-
-/**
- * Documentation can be found here:
- *
- * @see <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=">TwinCAT System Manager - I/O Variables</a>
- * @see <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tcplccontrol/html/tcplcctrl_plc_data_types_overview.htm&id">TwinCAT PLC Control: Data Types</a>
- */
-public enum AdsDataType {
-    // System-Manager versions of the IEC61131-3 datatypes.
-    // See: https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=
-    // For mapping
-    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((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
-    // Standard Data Types
-    /**
-     * BOOL type variables may be given the values TRUE and FALSE.
-     * <p>
-     * Type	Memory use
-     * BOOL	8 Bit
-     * Note:
-     * <p>
-     * A BOOL type variable is true, if the least significant bit in the memory is set (e.g. 2#00000001 ). If no bit is set in the memory, the variable is FALSE (2#00000000). All other values can´t be interpeted accurately and be displayed (***INVALID: 16#xy *** in the Online View). Such problems may appear, if for example overlapped memory ranges are used in the PLC program.
-     * <p>
-     * Example:
-     * <p>
-     * The boolean variable is in the same memory range as the byte variable.
-     */
-    BOOL((byte) 0, (byte) 1, 8),
-    /**
-     * BYTE
-     * <p>
-     * Integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * BYTE	0	255	8 Bit
-     */
-    BYTE((short) 0, (short) 255, 8),
-    /**
-     * WORD
-     * Integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * WORD	0	65535	16 Bit
-     */
-    WORD(0, 65535, 16),
-    /**
-     * DWORD
-     * Integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * DWORD	0	4294967295	32 Bit
-     */
-    DWORD(0L, 4294967295L, 32),
-    /**
-     * SINT
-     * (Short) signed integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * SINT	-128	127	8 Bit
-     */
-    SINT(Byte.MIN_VALUE, Byte.MAX_VALUE, 8),
-    /**
-     * USINT
-     * Unsigned (short) integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * USINT	0	255	8 Bit
-     */
-    USINT((short) 0, (short) 0xFF, 8),
-    /**
-     * INT
-     * Signed integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * INT	-32768	32767	16 Bit
-     */
-    INT(Short.MIN_VALUE, Short.MAX_VALUE, 16),
-    /**
-     * UINT
-     * Unsigned integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * UINT	0	65535	16 Bit
-     */
-    UINT(0, 65535, 16),
-    /**
-     * DINT
-     * Signed integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * DINT	-2147483648	2147483647	32 Bit
-     */
-    DINT(-2147483648, 2147483647, 32),
-    /**
-     * UDINT
-     * Unsigned integer data type.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * UDINT	0	4294967295	32 Bit
-     */
-    UDINT(0L, 4294967295L, 32),
-    /**
-     * LINT  (64 bit integer, currently not supported by TwinCAT)
-     */
-    LINT(Long.MIN_VALUE, Long.MAX_VALUE, 64),
-    /**
-     * ULINT (Unsigned 64 bit integer, currently not supported by TwinCAT)
-     */
-    ULINT(BigInteger.ZERO, produceUnsignedMaxValue(8), 64),
-    /**
-     * REAL
-     * 32 Bit floating point data type. It is required to represent rational numbers.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * REAL	~ -3.402823 x 1038	~ 3.402823 x 1038	32 Bit
-     */
-    REAL(-Float.MAX_VALUE, Float.MAX_VALUE, 32),
-    /**
-     * LREAL
-     * 64 Bit floating point data type. It is required to represent rational numbers.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * LREAL	~ -1.79769313486231E308	~ 1.79769313486232E308	64 Bit
-     */
-    LREAL(-Double.MAX_VALUE, Double.MAX_VALUE, 64),
-    /**
-     * STRING
-     * A STRING type variable can contain any string of characters. The size entry in the declaration determines how much memory space should be reserved for the variable. It refers to the number of characters in the string and can be placed in parentheses or square brackets.
-     * <p>
-     * Example of a string declaration with 35 characters:
-     * <p>
-     * str:STRING(35):='This is a String';
-     * Type	Memory use
-     * STRING
-     * If no size specification is given, the default size of 80 characters will be used: Memory use [Bytes] =  80 + 1 Byte for string terminated Null character;
-     * If string size specification is given: Memory use [Bytes] = String Size + 1 Byte for string terminated Null character);
-     */
-    STRING(81 * 8),
-    /**
-     * TIME
-     * Duration time. The most siginificant digit is one millisecond. The data type is handled internally like DWORD.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * TIME	T#0ms	T#71582m47s295ms	32 Bit
-     */
-    TIME(0L, Duration.ofMinutes(71582).plusSeconds(47).plusMillis(295).toMillis(), 32),
-    /**
-     * TIME_OF_DAY
-     * TOD
-     * Time of day. The most siginificant digit is one millisecond. The data type is handled internally like DWORD.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * TIME_OF_DAY
-     * TOD
-     * <p>
-     * TOD#00:00	TOD#1193:02:47.295	32 Bit
-     *///TODO: strange maximum
-    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.
-     * <p>
-     * Type	Lower bound	Upper bound	Memory use
-     * DATE	D#1970-01-01	D#2106-02-06	32 Bit
-     */
-    DATE(0L, TimeUnit.DAYS.toSeconds(ChronoUnit.DAYS.between(LocalDate.of(1970, 1, 1), LocalDate.of(2106, 2, 6))), 32),
-    /**
-     * DATE_AND_TIME
-     * DT
-     * Date and time. The most siginificant digit is one second. The data type is handled internally like DWORD.
-     * <p>
-     * Type	Lower  bound	Upper  bound	Memory use
-     * DATE_AND_TIME
-     * DT
-     * <p>
-     * DT#1970-01-01-00:00	DT#2106-02-06-06:28:15	32 Bit
-     */
-    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
-     * One-, two-, and three-dimensional fields (arrays) are supported as elementary data types. Arrays can be defined both in the declaration part of a POU and in the global variable lists.
-     * <p>
-     * Syntax:
-     * <p>
-     * &lt;Field_Name&gt;:ARRAY [&lt;LowLim1&gt;..&lt;UpLim1&gt;, &lt;LowLim2&gt;..&lt;UpLim2&gt;] OF &lt;elem. Type&gt;
-     * <p>
-     * LowLim1, LowLim2 identify the lower limit of the field range; UpLim1 and UpLim2 identify the upper limit. The range values must be integers.
-     * <p>
-     * Example:
-     * <p>
-     * Card_game: ARRAY [1..13, 1..4] OF INT;
-     * <p>
-     * <p>
-     * <p>
-     * Initializing of Arrays
-     * You can initialize either all of the elements in an array or none of them.
-     * <p>
-     * Example for initializing arrays:
-     * <p>
-     * arr1 : ARRAY [1..5] OF INT := 1,2,3,4,5;
-     * arr2 : ARRAY [1..2,3..4] OF INT := 1,3(7); (* short for 1,7,7,7 *)
-     * arr3 : ARRAY [1..2,2..3,3..4] OF INT := 2(0),4(4),2,3; (* short for 0,0,4,4,4,4,2,3 *)
-     * <p>
-     * <p>
-     * <p>
-     * Example for the initialization of an array of a structure:
-     * <p>
-     * TYPE STRUCT1
-     * STRUCT
-     * p1:int;
-     * p2:int;
-     * p3:dword;
-     * END_STRUCT
-     * arr1 : ARRAY[1..3] OF STRUCT1:= (p1:=1,p2:=10,p3:=4723), (p1:=2,p2:=0,p3:=299), (p1:=14,p2:=5,p3:=112);
-     * <p>
-     * <p>
-     * Example of the partial initialization of an Array:
-     * <p>
-     * arr1 : ARRAY [1..10] OF INT := 1,2;
-     * Elements to which no value is pre-assigned are initialized with the default initial value of the basic type. In the example above, the elements arr1[3]  to arr1[10] are therefore initialized with 0.
-     * <p>
-     * <p>
-     * <p>
-     * Array components are accessed in a two-dimensional array using the following syntax:
-     * <p>
-     * &lt;Field_Name&gt;[Index1,Index2]
-     * <p>
-     * Example:
-     * <p>
-     * Card_game[9,2]
-     * <p>
-     * <p>
-     * <p>
-     * Note:
-     * <p>
-     * If you define a function in your project with the name CheckBounds, you can automatically check for out-of-range errors in arrays ! The name of the function is fixed and can only have this designation.
-     */
-    ARRAY(-1),//TODO: implement me
-    /**
-     * Pointer
-     * Variable or function block addresses are saved in pointers while a program is running. Pointer declarations have the following syntax:
-     * <p>
-     * &lt;Identifier&gt;: POINTER TO &lt;Datatype/Functionblock&gt;;
-     * A pointer can point to any data type or function block even to user-defined types. The function of the Address Operator ADR is to assign the address of a variable or function block to the pointer.
-     * A pointer can be dereferenced by adding the content operator "^" after the pointer identifier. With the help of the SIZEOF Operator, e.g. a pointer increment can be done.
-     * <p>
-     * <p>
-     * Please note: A pointer is counted up byte-wise ! You can get it counted up like it is usual in the C-Compiler by using the instruction p=p+SIZEOF(p^);.
-     * <p>
-     * <p>
-     * <p>
-     * Attention:
-     * After an Online Change there might be changes concerning the data on certain addresses. Please regard this in case of using pointers on addresses.
-     * <p>
-     * <p>
-     * <p>
-     * Example:
-     * <p>
-     * pt:POINTER TO INT;
-     * var_int1:INT := 5;
-     * var_int2:INT;
-     * <p>
-     * <p>
-     * pt := ADR(var_int1);
-     * var_int2:= pt^; (* var_int2 is now 5 *)
-     * <p>
-     * <p>
-     * Example 2 (Pointer increment):
-     * <p>
-     * ptByCurrDataOffs : POINTER TO BYTE;
-     * udiAddress       : UDINT;
-     * <p>
-     * <p>
-     * <p>
-     * (*--- pointer increment ---*)
-     * udiAddress := ptByCurrDataOffs;
-     * udiAddress := udiAddress + SIZEOF(ptByCurrDataOffs^);
-     * ptByCurrDataOffs := udiAddress;
-     * (* -- end of pointer increment ---*)
-     */
-    POINTER(-1),//TODO: implement me,
-    /**
-     * Enumeration (ENUM)
-     * Enumeration is a user-defined data type that is made up of a number of string constants. These constants are referred to as enumeration values. Enumeration values are recognized in all areas of the project even if they were locally declared within aPOU. It is best to create your enumerations as objects in the Object Organizer under the register card Data types. They begin with the keyword TYPE and end with END_TYPE.
-     * <p>
-     * Syntax:
-     * <p>
-     * TYPE &lt;Identifier&gt;:(&lt;Enum_0&gt; ,&lt;Enum_1&gt;, ...,&lt;Enum_n&gt;);END_TYPE
-     * <p>
-     * The &lt;Identifier&gt; can take on one of the enumeration values and will be initialized with the first one. These values are compatible with whole numbers which means that you can perform operations with them just as you would with INT. You can assign a number x to the &lt;Identifier&gt;. If the enumeration values are not initialized, counting will begin with 0. When initializing, make certain the initial values are increasing. The validity of the number will be reviewed at the t [...]
-     * <p>
-     * Example:
-     * <p>
-     * TRAFFIC_SIGNAL: (Red, Yellow, Green:=10); (*The initial value for each of the colors is red 0, yellow 1, green 10 *)
-     * TRAFFIC_SIGNAL:=0; (* The value of the traffic signal is red*)
-     * FOR i:= Red TO Green DO
-     * i := i + 1;
-     * END_FOR;
-     * <p>
-     * You may not use the same enumeration value more than once.
-     * <p>
-     * Example:
-     * <p>
-     * TRAFFIC_SIGNAL: (red, yellow, green);
-     * COLOR: (blue, white, red);
-     * <p>
-     * Error: red may not be used for both TRAFFIC_SIGNAL and COLOR.
-     */
-    ENUM(-1),//TODO: implement me,
-    /**
-     * Structures (STRUCT)
-     * Structures are created as objects in the Object Organizer under the register card Data types. They begin with the keyword TYPE and end with END_TYPE.The syntax for structure declarations is as follows:
-     * <p>
-     * TYPE &lt;Structurename&gt;:
-     * STRUCT
-     * &lt;Declaration of Variables 1&gt;
-     * .
-     * .
-     * &lt;Declaration of Variables n&gt;
-     * END_STRUCT
-     * END_TYPE
-     * <p>
-     * &lt;Structurename&gt; is a type that is recognized throughout the project and can be used like a standard data type. Interlocking structures are allowed. The only restriction is that variables may not be placed at addresses (the AT declaration is not allowed!).
-     * <p>
-     * Example for a structure definition named Polygonline:
-     * <p>
-     * TYPE Polygonline:
-     * STRUCT
-     * Start:ARRAY [1..2] OF INT;
-     * Point1:ARRAY [1..2] OF INT;
-     * Point2:ARRAY [1..2] OF INT;
-     * Point3:ARRAY [1..2] OF INT;
-     * Point4:ARRAY [1..2] OF INT;
-     * End:ARRAY [1..2] OF INT;
-     * END_STRUCT
-     * END_TYPE
-     * <p>
-     * You can gain access to structure components using the following syntax:
-     * <p>
-     * &lt;Structure_Name&gt;.&lt;Componentname&gt;
-     * <p>
-     * For example, if you have a structure named "Week" that contains a component named "Monday", you can get to it by doing the following: Week.Monday
-     * <p>
-     * <p>
-     * <p>
-     * Note:
-     * Due to different alignments, structures and arrays may have different configurations and sizes on different hardware platforms (e.g. CX1000 and CX90xx).
-     * <p>
-     * During data exchange the size and structure alignment must be identical!
-     * <p>
-     * <p>
-     * <p>
-     * Example for a structure definition with name ST_ALIGN_SAMPLE:
-     * <p>
-     * TYPE ST_ALIGN_SAMPLE:
-     * STRUCT
-     * _diField1   : DINT;
-     * _byField1   : BYTE;
-     * _iField     : INT;
-     * _byField2   : BYTE;
-     * _diField2   : DINT;
-     * _pField     : POINTER TO BYTE;
-     * END_STRUCT
-     * END_TYPE
-     * <p>
-     * On CX90xx (RISC) platforms the member components of structure ST_ALIGN_SAMPLE have the following sizes and offsets:
-     * <p>
-     * _diField1 (DINT), Offset = 0 (16#0),   Size = 4
-     * _byField1 (BYTE), Offset = 4 (16#4),   Size = 1
-     * _iField (INT), Offset = 6 (16#6),   Size = 2
-     * _byField2 (BYTE), Offset = 8 (16#8),   Size = 1
-     * _diField2 (DINT), Offset = 12 (16#C),  Size = 4
-     * _pField (POINTER TO BYTE), Offset = 16 (16#10), Size = 4
-     * <p>
-     * Overall size through natural alignment with Pack(4) and so-called padding bytes: 20
-     * <p>
-     * <p>
-     * <p>
-     * On CX10xx platforms the member components of structure ST_ALIGN_SAMPLE have the following sizes and offsets:
-     * <p>
-     * _diField1 (DINT), Offset = 0 (16#0),   Size = 4
-     * _byField1 (BYTE), Offset = 4 (16#4),   Size = 1
-     * _iField (INT), Offset = 5 (16#5),   Size = 2
-     * _byField2 (BYTE), Offset = 7 (16#7),   Size = 1
-     * _diField2 (DINT), Offset = 8 (16#8),  Size = 4
-     * _pField (POINTER TO BYTE), Offset = 12 (16#C), Size = 4
-     * <p>
-     * Overall size: 16
-     * <p>
-     * <p>
-     * <p>
-     * Display of structure ST_ALIGN_SAMPLE for CX90xx platforms (RISC) with representation of the padding bytes:
-     * <p>
-     * TYPE ST_ALIGN_SAMPLE:
-     * STRUCT
-     * _diField1    : DINT;
-     * _byField1    : BYTE;
-     * _byPadding   : BYTE;
-     * _iField      : INT;
-     * _byField2    : BYTE;
-     * _a_byPadding : ARRAY[0..2] OF BYTE;
-     * _diField2    : DINT;
-     * _pField      : POINTER TO BYTE;
-     * END_STRUCT
-     * END_TYPE
-     */
-    STRUCT(-1),//TODO: implement me,
-    /**
-     * References (Alias types)
-     * You can use the user-defined derived data type to create an alternative name for a variable, constant or function block. Create your references as objects in the Object Organizer under the register card Data types. They begin with the keyword TYPE and end with END_TYPE.
-     * <p>
-     * Syntax:
-     * <p>
-     * TYPE &lt;Identifier&gt;: &lt;Assignment term&gt;;
-     * END_TYPE
-     * <p>
-     * Example:
-     * <p>
-     * TYPE message:STRING[50];
-     * END_TYPE;
-     */
-    ALIAS(-1),//TODO: implement me,
-    /**
-     * Subrange types
-     * A sub-range data type is a type whose range of values is only a subset of that of the basic type. The declaration can be carried out in the data types register, but a variable can also be directly declared with a subrange type:
-     * Syntax for the declaration in the 'Data types' register:
-     * <p>
-     * TYPE &lt;Name&gt; : &lt;Inttype&gt; (&lt;ug&gt;..&lt;og&gt;) END_TYPE;
-     * Type	Description
-     * &lt;Name&gt;	must be a valid IEC identifier
-     * &lt;Inttype&gt;	is one of the data types SINT, USINT, INT, UINT, DINT, UDINT, BYTE, WORD, DWORD (LINT, ULINT, LWORD).
-     * &lt;ug&gt;	Is a constant which must be compatible with the basic type and which sets the lower boundary of the range types. The lower boundary itself is included in this range.
-     * &lt;og&gt;	Is a constant that must be compatible with the basic type, and sets the upper boundary of the range types. The upper boundary itself is included in this basic type.
-     * Example:
-     * <p>
-     * TYPE
-     * SubInt : INT (-4095..4095);
-     * END_TYPE
-     * Direct declaration of a variable with a subrange type:
-     * <p>
-     * VAR
-     * i1 : INT (-4095..4095);
-     * i2: INT (5...10):=5;
-     * ui : UINT (0..10000);
-     * END_VAR
-     * If a constant is assigned to a subrange type (in the declaration or in the implementation) that does not apply to this range (e.g. 1:=5000), an error message is issued.
-     * In order to check for observance of range boundaries at runtime, the functions CheckRangeSigned or CheckRangeUnsigned must be introduced.
-     */
-    SUB_RANGE_DATA_TYPE(-1),//TODO: implement me,
-
-    UNKNOWN(-1);
-
-    private final String typeName;
-
-    private final Number lowerBound;
-
-    private final double lowerBoundDouble;
-
-    private final Number upperBound;
-
-    private final double upperBoundDouble;
-
-    private final int memoryUse;
-
-    private final int targetByteSize;
-
-    // TODO: BYTE.MAX default might not be the best....
-    AdsDataType(int memoryUse) {
-        this(0, Byte.MAX_VALUE, 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;
-    }
-
-    public String getTypeName() {
-        return typeName;
-    }
-
-    public Number getLowerBound() {
-        return lowerBound;
-    }
-
-    public Number getUpperBound() {
-        return upperBound;
-    }
-
-    public int getMemoryUse() {
-        return memoryUse;
-    }
-
-    public int getTargetByteSize() {
-        return targetByteSize;
-    }
-
-    public boolean withinBounds(double other) {
-        return other >= lowerBoundDouble && other <= upperBoundDouble;
-    }
-
-    @Override
-    public String toString() {
-        return "AdsDataType{" +
-            "typeName='" + typeName + '\'' +
-            ", lowerBound=" + lowerBound +
-            ", upperBound=" + upperBound +
-            ", memoryUse=" + memoryUse +
-            ", targetByteSize=" + targetByteSize +
-            "} " + super.toString();
-    }
-
-    private static BigInteger produceUnsignedMaxValue(int numberOfBytes) {
-        return new BigInteger(
-            ArrayUtils.insert(
-                0,
-                IntStream.range(0, numberOfBytes)
-                    .map(ignore -> 0xff)
-                    .collect(
-                        ByteArrayOutputStream::new,
-                        (baos, i) -> baos.write((byte) i),
-                        (baos1, baos2) -> baos1.write(baos2.toByteArray(), 0, baos2.size())
-                    )
-                    .toByteArray(),
-                (byte) 0x0)
-        );
-    }
-}
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/EIPDriver.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/EIPDriver.java
index 8a147f1..799f332 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/EIPDriver.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/EIPDriver.java
@@ -24,7 +24,7 @@ import org.apache.plc4x.java.eip.readwrite.field.EipField;
 import org.apache.plc4x.java.eip.readwrite.field.EipFieldHandler;
 import org.apache.plc4x.java.eip.readwrite.io.EipPacketIO;
 import org.apache.plc4x.java.eip.readwrite.protocol.EipProtocolLogic;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipFieldHandler.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipFieldHandler.java
index 504f30e..3aabe51 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipFieldHandler.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipFieldHandler.java
@@ -19,21 +19,11 @@
 package org.apache.plc4x.java.eip.readwrite.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.eip.readwrite.types.CIPDataTypeCode;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.lang.reflect.InvocationTargetException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
+public class EipFieldHandler implements PlcFieldHandler {
 
-public class EipFieldHandler extends DefaultPlcFieldHandler {
     @Override
     public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
        if(EipField.matches(fieldQuery)){
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
index d811314..ae63f20 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
@@ -37,6 +37,7 @@ import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.messages.*;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.apache.plc4x.java.spi.values.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -105,7 +106,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
             CipReadRequest req = new CipReadRequest(getRequestSize(tag), toAnsi(tag), elements);
             requests.add(req);
         }
-        return toPlcReadResponse((InternalPlcReadRequest) readRequest, readInternal(requests));
+        return toPlcReadResponse(readRequest, readInternal(requests));
     }
 
     private byte getRequestSize(String tag) {
@@ -177,7 +178,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
         return buffer.array();
     }
 
-    private CompletableFuture<PlcReadResponse> toPlcReadResponse(InternalPlcReadRequest readRequest, CompletableFuture<CipService> response) {
+    private CompletableFuture<PlcReadResponse> toPlcReadResponse(PlcReadRequest readRequest, CompletableFuture<CipService> response) {
         return response
             .thenApply(p -> {
                 return ((PlcReadResponse) decodeReadResponse(p, readRequest));
@@ -250,7 +251,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
         return future;
     }
 
-    private PlcResponse decodeReadResponse(CipService p, InternalPlcReadRequest readRequest) {
+    private PlcResponse decodeReadResponse(CipService p, PlcReadRequest readRequest) {
         Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
         // only 1 field
         if (p instanceof CipReadResponse) {
@@ -421,7 +422,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
                 .check(p -> p.getExchange().getService() instanceof CipWriteResponse)
                 .unwrap(p -> (CipWriteResponse) p.getExchange().getService())
                 .handle(p -> {
-                    future.complete((PlcWriteResponse) decodeWriteResponse(p, ((InternalPlcWriteRequest) writeRequest)));
+                    future.complete((PlcWriteResponse) decodeWriteResponse(p, writeRequest));
                     transaction.endRequest();
                 })
             );
@@ -462,7 +463,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
                 .unwrap(p -> (MultipleServiceResponse) p)
                 .check(p -> p.getServiceNb() == nb)
                 .handle(p -> {
-                    future.complete((PlcWriteResponse) decodeWriteResponse(p, ((InternalPlcWriteRequest) writeRequest)));
+                    future.complete((PlcWriteResponse) decodeWriteResponse(p, writeRequest));
                     // Finish the request-transaction.
                     transaction.endRequest();
                 }));
@@ -470,7 +471,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
         return future;
     }
 
-    private PlcResponse decodeWriteResponse(CipService p, InternalPlcWriteRequest writeRequest) {
+    private PlcResponse decodeWriteResponse(CipService p, PlcWriteRequest writeRequest) {
         Map<String, PlcResponseCode> responses = new HashMap<>();
 
         if (p instanceof CipWriteResponse) {
diff --git a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/FirmataDriver.java b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/FirmataDriver.java
index 6174a74..f5a396a 100644
--- a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/FirmataDriver.java
+++ b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/FirmataDriver.java
@@ -26,7 +26,7 @@ import org.apache.plc4x.java.firmata.readwrite.field.FirmataField;
 import org.apache.plc4x.java.firmata.readwrite.field.FirmataFieldHandler;
 import org.apache.plc4x.java.firmata.readwrite.io.FirmataMessageIO;
 import org.apache.plc4x.java.firmata.readwrite.protocol.FirmataProtocolLogic;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
diff --git a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/context/FirmataDriverContext.java b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/context/FirmataDriverContext.java
index 482da80..03577fe 100644
--- a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/context/FirmataDriverContext.java
+++ b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/context/FirmataDriverContext.java
@@ -23,14 +23,13 @@ import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcList;
+import org.apache.plc4x.java.spi.values.PlcList;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.firmata.readwrite.*;
 import org.apache.plc4x.java.firmata.readwrite.field.FirmataFieldAnalog;
 import org.apache.plc4x.java.firmata.readwrite.field.FirmataFieldDigital;
 import org.apache.plc4x.java.firmata.readwrite.types.PinMode;
 import org.apache.plc4x.java.spi.context.DriverContext;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 
 import java.util.*;
 
@@ -49,14 +48,13 @@ public class FirmataDriverContext implements DriverContext {
     public List<FirmataMessage> processWriteRequest(PlcWriteRequest writeRequest) {
         List<FirmataMessage> messages = new LinkedList<>();
 
-        InternalPlcWriteRequest internalPlcWriteRequest = (InternalPlcWriteRequest) writeRequest;
         for (String fieldName : writeRequest.getFieldNames()) {
             if(!(writeRequest.getField(fieldName) instanceof FirmataFieldDigital)) {
                 throw new PlcRuntimeException("Writing only supported for digital pins");
             }
 
             FirmataFieldDigital digitalField = (FirmataFieldDigital) writeRequest.getField(fieldName);
-            final PlcValue plcValue = internalPlcWriteRequest.getPlcValue(fieldName);
+            final PlcValue plcValue = writeRequest.getPlcValue(fieldName);
             if((digitalField.getNumberOfElements() > 1) && plcValue.isList()) {
                 final PlcList plcList = (PlcList) plcValue;
                 if(plcList.getList().size() != digitalField.getNumberOfElements()) {
diff --git a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/field/FirmataFieldHandler.java b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/field/FirmataFieldHandler.java
index be2b997..d07bb41 100644
--- a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/field/FirmataFieldHandler.java
+++ b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/field/FirmataFieldHandler.java
@@ -20,15 +20,9 @@ package org.apache.plc4x.java.firmata.readwrite.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
-public class FirmataFieldHandler extends DefaultPlcFieldHandler {
+public class FirmataFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
@@ -39,4 +33,5 @@ public class FirmataFieldHandler extends DefaultPlcFieldHandler {
         }
         throw new PlcInvalidFieldException(fieldQuery);
     }
+
 }
diff --git a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/protocol/FirmataProtocolLogic.java b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/protocol/FirmataProtocolLogic.java
index 32c9447..89d7905 100644
--- a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/protocol/FirmataProtocolLogic.java
+++ b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/protocol/FirmataProtocolLogic.java
@@ -36,7 +36,9 @@ import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.messages.*;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
+import org.apache.plc4x.java.spi.values.PlcBOOL;
+import org.apache.plc4x.java.spi.values.PlcDINT;
+import org.apache.plc4x.java.spi.values.PlcList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -98,7 +100,7 @@ public class FirmataProtocolLogic extends Plc4xProtocolBase<FirmataMessage> impl
             for (String fieldName : writeRequest.getFieldNames()) {
                 result.put(fieldName, PlcResponseCode.OK);
             }
-            future.complete(new DefaultPlcWriteResponse((InternalPlcWriteRequest) writeRequest, result));
+            future.complete(new DefaultPlcWriteResponse(writeRequest, result));
         } catch (PlcRuntimeException e) {
             future.completeExceptionally(e);
         }
@@ -120,7 +122,7 @@ public class FirmataProtocolLogic extends Plc4xProtocolBase<FirmataMessage> impl
                 result.put(fieldName, new ResponseItem<>(PlcResponseCode.OK,
                     new FirmataSubscriptionHandle(this, fieldName, field)));
             }
-            future.complete(new DefaultPlcSubscriptionResponse((InternalPlcSubscriptionRequest) subscriptionRequest, result));
+            future.complete(new DefaultPlcSubscriptionResponse(subscriptionRequest, result));
         } catch (PlcRuntimeException e) {
             future.completeExceptionally(e);
         }
@@ -180,7 +182,7 @@ public class FirmataProtocolLogic extends Plc4xProtocolBase<FirmataMessage> impl
     @Override
     public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> collection) {
         final DefaultPlcConsumerRegistration consumerRegistration =
-            new DefaultPlcConsumerRegistration(this, consumer, collection.toArray(new InternalPlcSubscriptionHandle[0]));
+            new DefaultPlcConsumerRegistration(this, consumer, collection.toArray(new PlcSubscriptionHandle[0]));
         consumers.put(consumerRegistration, consumer);
         return consumerRegistration;
     }
@@ -197,7 +199,7 @@ public class FirmataProtocolLogic extends Plc4xProtocolBase<FirmataMessage> impl
             final DefaultPlcConsumerRegistration registration = entry.getKey();
             final Consumer<PlcSubscriptionEvent> consumer = entry.getValue();
             // Only if the current data point matches the subscription, publish the event to it.
-            for (InternalPlcSubscriptionHandle handle : registration.getAssociatedHandles()) {
+            for (PlcSubscriptionHandle handle : registration.getSubscriptionHandles()) {
                 if (handle instanceof FirmataSubscriptionHandle) {
                     FirmataSubscriptionHandle subscriptionHandle = (FirmataSubscriptionHandle) handle;
                     // Check if the subscription matches this current event
@@ -236,7 +238,7 @@ public class FirmataProtocolLogic extends Plc4xProtocolBase<FirmataMessage> impl
             final DefaultPlcConsumerRegistration registration = entry.getKey();
             final Consumer<PlcSubscriptionEvent> consumer = entry.getValue();
             // Only if the current data point matches the subscription, publish the event to it.
-            for (InternalPlcSubscriptionHandle handle : registration.getAssociatedHandles()) {
+            for (PlcSubscriptionHandle handle : registration.getSubscriptionHandles()) {
                 if(handle instanceof FirmataSubscriptionHandle) {
                     FirmataSubscriptionHandle subscriptionHandle = (FirmataSubscriptionHandle) handle;
                     // Check if the subscription matches this current event
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
index 630d839..102b688 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
@@ -27,7 +27,7 @@ import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.knxnetip.field.KnxNetIpFieldHandler;
 import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocolLogic;
 import org.apache.plc4x.java.knxnetip.readwrite.KNXNetIPMessage;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/field/KnxNetIpFieldHandler.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/field/KnxNetIpFieldHandler.java
index a76e0b3..8c34d51 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/field/KnxNetIpFieldHandler.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/field/KnxNetIpFieldHandler.java
@@ -20,14 +20,9 @@ package org.apache.plc4x.java.knxnetip.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.api.value.PlcValues;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-public class KnxNetIpFieldHandler extends DefaultPlcFieldHandler {
+public class KnxNetIpFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
index fdbbcbf..9edecd8 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
@@ -49,8 +49,9 @@ import org.apache.plc4x.java.spi.generation.WriteBuffer;
 import org.apache.plc4x.java.spi.messages.*;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.apache.plc4x.java.spi.values.PlcSTRING;
+import org.apache.plc4x.java.spi.values.PlcStruct;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -516,13 +517,13 @@ public class KnxNetIpProtocolLogic extends Plc4xProtocolBase<KNXNetIPMessage> im
             }
         }
         return CompletableFuture.completedFuture(
-            new DefaultPlcSubscriptionResponse((InternalPlcSubscriptionRequest) subscriptionRequest, values));
+            new DefaultPlcSubscriptionResponse(subscriptionRequest, values));
     }
 
     @Override
     public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> collection) {
         final DefaultPlcConsumerRegistration consumerRegistration =
-            new DefaultPlcConsumerRegistration(this, consumer, collection.toArray(new InternalPlcSubscriptionHandle[0]));
+            new DefaultPlcConsumerRegistration(this, consumer, collection.toArray(new PlcSubscriptionHandle[0]));
         consumers.put(consumerRegistration, consumer);
         return consumerRegistration;
     }
@@ -544,7 +545,7 @@ public class KnxNetIpProtocolLogic extends Plc4xProtocolBase<KNXNetIPMessage> im
             final DefaultPlcConsumerRegistration registration = entry.getKey();
             final Consumer<PlcSubscriptionEvent> consumer = entry.getValue();
             // Only if the current data point matches the subscription, publish the event to it.
-            for (InternalPlcSubscriptionHandle handle : registration.getAssociatedHandles()) {
+            for (PlcSubscriptionHandle handle : registration.getSubscriptionHandles()) {
                 if(handle instanceof KnxNetIpSubscriptionHandle) {
                     KnxNetIpSubscriptionHandle subscriptionHandle = (KnxNetIpSubscriptionHandle) handle;
                     // Check if the subscription matches this current event.
diff --git a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/connection/MockConnection.java b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/connection/MockConnection.java
index fa68b44..4653a6f 100644
--- a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/connection/MockConnection.java
+++ b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/connection/MockConnection.java
@@ -29,6 +29,7 @@ import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.mock.field.MockField;
 import org.apache.plc4x.java.mock.field.MockFieldHandler;
+import org.apache.plc4x.java.mock.field.MockValueHandler;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest;
@@ -187,7 +188,7 @@ public class MockConnection implements PlcConnection, PlcReader, PlcWriter, PlcS
 
     @Override
     public PlcWriteRequest.Builder writeRequestBuilder() {
-        return new DefaultPlcWriteRequest.Builder(this, new MockFieldHandler());
+        return new DefaultPlcWriteRequest.Builder(this, new MockFieldHandler(), new MockValueHandler());
     }
 
     @Override
diff --git a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockFieldHandler.java b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockFieldHandler.java
index 16479c5..7bb86dc 100644
--- a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockFieldHandler.java
+++ b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockFieldHandler.java
@@ -20,79 +20,13 @@
 package org.apache.plc4x.java.mock.field;
 
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-public class MockFieldHandler extends DefaultPlcFieldHandler {
+public class MockFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
         return new MockField(fieldQuery);
     }
 
-    @Override
-    public PlcValue encodeBoolean(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeByte(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeShort(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeInteger(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeBigInteger(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeLong(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeFloat(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeBigDecimal(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeDouble(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeString(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeTime(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeDate(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
-    @Override
-    public PlcValue encodeDateTime(PlcField field, Object[] values) {
-        return new MockPlcValue(values);
-    }
-
 }
diff --git a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockPlcValue.java b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockPlcValue.java
index f0c71c9..c27e6a0 100644
--- a/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockPlcValue.java
+++ b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockPlcValue.java
@@ -19,7 +19,9 @@
 
 package org.apache.plc4x.java.mock.field;
 
-import org.apache.plc4x.java.api.value.PlcValueAdapter;
+import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException;
+import org.apache.plc4x.java.spi.values.PlcValueAdapter;
+import org.w3c.dom.Element;
 
 public class MockPlcValue extends PlcValueAdapter {
 
@@ -33,4 +35,9 @@ public class MockPlcValue extends PlcValueAdapter {
         return values[index];
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        throw new PlcNotImplementedException("Not implemented");
+    }
+
 }
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockValueHandler.java
similarity index 65%
copy from plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
copy to plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockValueHandler.java
index e2adebf..fc47f33 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
+++ b/plc4j/drivers/mock/src/main/java/org/apache/plc4x/java/mock/field/MockValueHandler.java
@@ -16,14 +16,21 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.modbus;
+package org.apache.plc4x.java.mock.field;
 
-import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.api.value.PlcValueHandler;
 
-public class ModbusIOTest extends ParserSerializerTestsuiteRunner {
+public class MockValueHandler implements PlcValueHandler {
 
-    public ModbusIOTest() {
-        super("/protocols/modbus/ParserSerializerTestsuite.xml");
+    @Override
+    public PlcValue of(Object value) {
+        return new MockPlcValue(value);
+    }
+
+    @Override
+    public PlcValue of(Object[] values) {
+        return new MockPlcValue(values);
     }
 
 }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
index f1b04d5..d833543 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
@@ -25,7 +25,7 @@ import org.apache.plc4x.java.modbus.field.ModbusFieldHandler;
 import org.apache.plc4x.java.modbus.protocol.ModbusProtocolLogic;
 import org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU;
 import org.apache.plc4x.java.modbus.readwrite.io.ModbusTcpADUIO;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
index 9e92901..bbf96cd 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
@@ -18,14 +18,18 @@ under the License.
 */
 package org.apache.plc4x.java.modbus.field;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.modbus.readwrite.types.*;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Objects;
 import java.util.regex.Pattern;
 
-public abstract class ModbusField implements PlcField {
+public abstract class ModbusField implements PlcField, XmlSerializable {
 
     public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?<address>\\d+)(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
     public static final Pattern FIXED_DIGIT_MODBUS_PATTERN = Pattern.compile("(?<address>\\d{4,5})?(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
@@ -82,6 +86,7 @@ public abstract class ModbusField implements PlcField {
         return quantity * ModbusDataTypeSizes.enumForValue(dataType).getDataTypeSize();
     }
 
+    @JsonIgnore
     public int getLengthWords() {
         return (int) (quantity * ((float) ModbusDataTypeSizes.enumForValue(dataType).getDataTypeSize())/2.0f);
     }
@@ -125,4 +130,22 @@ public abstract class ModbusField implements PlcField {
             '}';
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement(getClass().getSimpleName());
+        parent.appendChild(messageElement);
+        Element addressElement = doc.createElement("address");
+        addressElement.appendChild(doc.createTextNode(Integer.toString(getAddress())));
+        messageElement.appendChild(addressElement);
+
+        Element quantityElement = doc.createElement("numberOfElements");
+        quantityElement.appendChild(doc.createTextNode(Integer.toString(getNumberOfElements())));
+        messageElement.appendChild(quantityElement);
+
+        Element datatypeElement = doc.createElement("dataType");
+        datatypeElement.appendChild(doc.createTextNode(getDataType()));
+        messageElement.appendChild(datatypeElement);
+    }
+
 }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
index b7fddb4..909f1be 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
@@ -19,21 +19,10 @@ under the License.
 package org.apache.plc4x.java.modbus.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
-import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.math.BigInteger;
-import java.math.BigDecimal;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
-public class ModbusFieldHandler extends DefaultPlcFieldHandler {
+public class ModbusFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
index df04f38..0b20229 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
@@ -46,6 +46,8 @@ import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.plc4x.java.spi.values.PlcBOOL;
+import org.apache.plc4x.java.spi.values.PlcList;
 
 import java.time.Duration;
 import java.util.ArrayList;
@@ -452,7 +454,7 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> impleme
         // they are ordered like this: 8 7 6 5 4 3 2 1 | 0 0 0 0 0 0 0 9
         // Luckily it turns out that this is exactly how BitSet parses byte[]
         BitSet bits = BitSet.valueOf(data);
-        List<PlcBOOL> result = new ArrayList<>(count);
+        List<PlcValue> result = new ArrayList<>(count);
         for(int i = 0; i < count; i++) {
             result.add(new PlcBOOL(bits.get(i)));
         }
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusEncodeTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusEncodeTest.java
index cdd1d15..59ee99c 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusEncodeTest.java
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusEncodeTest.java
@@ -19,16 +19,13 @@ under the License.
 package org.apache.plc4x.java.modbus;
 
 import org.apache.plc4x.java.modbus.field.ModbusFieldHoldingRegister;
-import org.apache.plc4x.java.modbus.field.ModbusFieldInputRegister;
-import org.apache.plc4x.java.modbus.field.ModbusExtendedRegister;
-import org.apache.plc4x.java.modbus.field.ModbusFieldDiscreteInput;
 import org.apache.plc4x.java.modbus.field.ModbusFieldCoil;
-import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.modbus.field.*;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.PlcList;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import java.math.BigInteger;
-import java.math.BigDecimal;
 
 public class ModbusEncodeTest {
 
@@ -36,8 +33,7 @@ public class ModbusEncodeTest {
     public void testEncodeBooleanBOOL() {
         Boolean[] object = {true,false,true,false,true,false,true,true,false};
         ModbusFieldCoil coils = ModbusFieldCoil.of("coil:8:BOOL");
-        ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeBoolean(coils, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(coils, object);
         Assertions.assertEquals("[true,false,true,false,true,false,true,true,false]", list.toString());
     }
 
@@ -46,7 +42,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,-1,127,-128,5,6,7,8};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:8:SINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,-1,127,-128,5,6,7,8]", list.toString());
     }
 
@@ -55,7 +51,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,255,0,4,5,6,7,8};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:8:USINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,255,0,4,5,6,7,8]", list.toString());
     }
 
@@ -64,7 +60,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,255,0,4,5,6,7,8};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:8:BYTE");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,255,0,4,5,6,7,8]", list.toString());
     }
 
@@ -73,7 +69,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,-1,32000,-32000,5,6,7};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:INT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,-1,32000,-32000,5,6,7]", list.toString());
     }
 
@@ -82,7 +78,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,65535,10,55000,5,6,7};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:UINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,65535,10,55000,5,6,7]", list.toString());
     }
 
@@ -91,7 +87,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,65535,10,55000,5,6,7};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:WORD");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,65535,10,55000,5,6,7]", list.toString());
     }
 
@@ -100,7 +96,7 @@ public class ModbusEncodeTest {
         Integer[] object = {1,655354775,-2147483648,2147483647,5,6,7};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:DINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,-2147483648,2147483647,5,6,7]", list.toString());
     }
 
@@ -109,7 +105,7 @@ public class ModbusEncodeTest {
         Long[] object = {1L,655354775L,0L,4294967295L,5L,6L,7L};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:UDINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeLong(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,0,4294967295,5,6,7]", list.toString());
     }
 
@@ -118,7 +114,7 @@ public class ModbusEncodeTest {
         Long[] object = {1L,655354775L,0L,4294967295L,5L,6L,7L};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:DWORD");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeLong(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,0,4294967295,5,6,7]", list.toString());
     }
 
@@ -127,7 +123,7 @@ public class ModbusEncodeTest {
         Long[] object = {1L,655354775L,-9223372036854775808L,9223372036854775807L,5L,6L,7L};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:LINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeLong(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,-9223372036854775808,9223372036854775807,5,6,7]", list.toString());
     }
 
@@ -136,7 +132,7 @@ public class ModbusEncodeTest {
         BigInteger[] object = {BigInteger.valueOf(1L),BigInteger.valueOf(655354775L),BigInteger.valueOf(0),new BigInteger("18446744073709551615"),BigInteger.valueOf(5L),BigInteger.valueOf(6L),BigInteger.valueOf(7L)};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:ULINT");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeBigInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,0,18446744073709551615,5,6,7]", list.toString());
     }
 
@@ -145,7 +141,7 @@ public class ModbusEncodeTest {
         BigInteger[] object = {BigInteger.valueOf(1L),BigInteger.valueOf(655354775L),BigInteger.valueOf(0),new BigInteger("18446744073709551615"),BigInteger.valueOf(5L),BigInteger.valueOf(6L),BigInteger.valueOf(7L)};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:LWORD");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeBigInteger(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1,655354775,0,18446744073709551615,5,6,7]", list.toString());
     }
 
@@ -154,7 +150,7 @@ public class ModbusEncodeTest {
         Float[] object = {1.1f,1000.1f,100000.1f,3.4028232E38f,-3.4028232E38f,-1f,10384759934840.0f};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:REAL");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeFloat(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1.1,1000.1,100000.1,3.4028233E38,-3.4028233E38,-1.0,1.03847601E13]", list.toString());
     }
 
@@ -163,7 +159,7 @@ public class ModbusEncodeTest {
         Double[] object = {1.1,1000.1,100000.1,1.7E308,-1.7E308,-1d,10384759934840.0};
         ModbusFieldHoldingRegister holdingregister = ModbusFieldHoldingRegister.of("holding-register:7:LREAL");
         ModbusFieldHandler handler = new ModbusFieldHandler();
-        PlcList list = (PlcList) handler.encodeDouble(holdingregister, object);
+        PlcList list = (PlcList) IEC61131ValueHandler.newPlcValue(holdingregister, object);
         Assertions.assertEquals("[1.1,1000.1,100000.1,1.7E308,-1.7E308,-1.0,1.038475993484E13]", list.toString());
     }
 
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusParserSerializerTest.java
similarity index 88%
copy from plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
copy to plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusParserSerializerTest.java
index e2adebf..3646dc6 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusParserSerializerTest.java
@@ -20,9 +20,9 @@ package org.apache.plc4x.java.modbus;
 
 import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
 
-public class ModbusIOTest extends ParserSerializerTestsuiteRunner {
+public class ModbusParserSerializerTest extends ParserSerializerTestsuiteRunner {
 
-    public ModbusIOTest() {
+    public ModbusParserSerializerTest() {
         super("/protocols/modbus/ParserSerializerTestsuite.xml");
     }
 
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/BaseOpcuaPlcConnection.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/BaseOpcuaPlcConnection.java
index 2a67f62..feedc43 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/BaseOpcuaPlcConnection.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/BaseOpcuaPlcConnection.java
@@ -26,6 +26,7 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.opcua.protocol.OpcuaPlcFieldHandler;
 import org.apache.plc4x.java.spi.connection.AbstractPlcConnection;
 import org.apache.plc4x.java.spi.messages.*;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -78,7 +79,7 @@ public abstract class BaseOpcuaPlcConnection extends AbstractPlcConnection imple
 
     @Override
     public PlcWriteRequest.Builder writeRequestBuilder() {
-        return new DefaultPlcWriteRequest.Builder(this, new OpcuaPlcFieldHandler());
+        return new DefaultPlcWriteRequest.Builder(this, new OpcuaPlcFieldHandler(), new IEC61131ValueHandler());
     }
 
     @Override
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java
index 0a42caa..236be6c 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java
@@ -24,6 +24,7 @@ import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.*;
@@ -31,7 +32,9 @@ import org.apache.plc4x.java.opcua.protocol.OpcuaField;
 import org.apache.plc4x.java.opcua.protocol.OpcuaSubsriptionHandle;
 import org.apache.plc4x.java.spi.messages.*;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
+import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
+import org.apache.plc4x.java.spi.values.*;
 import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
 import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
 import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
@@ -283,75 +286,71 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
 
     @Override
     public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
-        InternalPlcSubscriptionRequest internalPlcSubscriptionRequest = checkInternal(subscriptionRequest, InternalPlcSubscriptionRequest.class);
         CompletableFuture<PlcSubscriptionResponse> future = CompletableFuture.supplyAsync(() -> {
-            Map<String, ResponseItem<PlcSubscriptionHandle>> responseItems = internalPlcSubscriptionRequest.getSubscriptionPlcFieldMap().entrySet().stream()
-                .map(subscriptionPlcFieldEntry -> {
-                    final String plcFieldName = subscriptionPlcFieldEntry.getKey();
-                    final SubscriptionPlcField subscriptionPlcField = subscriptionPlcFieldEntry.getValue();
-                    final OpcuaField field = (OpcuaField) Objects.requireNonNull(subscriptionPlcField.getPlcField());
-                    long cycleTime = subscriptionPlcField.getDuration().orElse(Duration.ofSeconds(1)).toMillis();
-                    NodeId idNode = generateNodeId(field);
-                    ReadValueId readValueId = new ReadValueId(
-                        idNode,
-                        AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE);
-                    UInteger clientHandle = uint(clientHandles.getAndIncrement());
-
-                    MonitoringParameters parameters = new MonitoringParameters(
-                        clientHandle,
-                        (double) cycleTime,     // sampling interval
-                        null,       // filter, null means use default
-                        uint(1),   // queue size
-                        true        // discard oldest
-                    );
-                    MonitoringMode monitoringMode;
-                    switch (subscriptionPlcField.getPlcSubscriptionType()) {
-                        case CYCLIC:
-                            monitoringMode = MonitoringMode.Sampling;
-                            break;
-                        case CHANGE_OF_STATE:
-                            monitoringMode = MonitoringMode.Reporting;
-                            break;
-                        case EVENT:
-                            monitoringMode = MonitoringMode.Reporting;
-                            break;
-                        default:
-                            monitoringMode = MonitoringMode.Reporting;
-                    }
-
-                    PlcSubscriptionHandle subHandle = null;
-                    PlcResponseCode responseCode = PlcResponseCode.ACCESS_DENIED;
-                    try {
-                        UaSubscription subscription = client.getSubscriptionManager().createSubscription(cycleTime).get();
-
-                        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
-                            readValueId, monitoringMode, parameters);
-                        List<MonitoredItemCreateRequest> requestList = new LinkedList<>();
-                        requestList.add(request);
-                        OpcuaSubsriptionHandle subsriptionHandle = new OpcuaSubsriptionHandle(plcFieldName, clientHandle);
-                        BiConsumer<UaMonitoredItem, Integer> onItemCreated =
-                            (item, id) -> item.setValueConsumer(subsriptionHandle::onSubscriptionValue);
-
-                        List<UaMonitoredItem> items = subscription.createMonitoredItems(
-                            TimestampsToReturn.Both,
-                            requestList,
-                            onItemCreated
-                        ).get();
-
-                        subHandle = subsriptionHandle;
-                        responseCode = PlcResponseCode.OK;
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                        logger.warn("Unable to subscribe Elements because of: {}", e.getMessage());
-                    } catch (ExecutionException e) {
-                        logger.warn("Unable to subscribe Elements because of: {}", e.getMessage());
-                    }
+            Map<String, ResponseItem<PlcSubscriptionHandle>> responseItems = new HashMap<>();
+            for (String fieldName : subscriptionRequest.getFieldNames()) {
+                final PlcSubscriptionField subscriptionField = subscriptionRequest.getField(fieldName);
+                final OpcuaField field = (OpcuaField) Objects.requireNonNull(subscriptionField);
+                long cycleTime = subscriptionField.getDuration().orElse(Duration.ofSeconds(1)).toMillis();
+                NodeId idNode = generateNodeId(field);
+                ReadValueId readValueId = new ReadValueId(
+                    idNode,
+                    AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE);
+                UInteger clientHandle = uint(clientHandles.getAndIncrement());
+
+                MonitoringParameters parameters = new MonitoringParameters(
+                    clientHandle,
+                    (double) cycleTime,     // sampling interval
+                    null,       // filter, null means use default
+                    uint(1),   // queue size
+                    true        // discard oldest
+                );
+                MonitoringMode monitoringMode;
+                switch (subscriptionField.getPlcSubscriptionType()) {
+                    case CYCLIC:
+                        monitoringMode = MonitoringMode.Sampling;
+                        break;
+                    case CHANGE_OF_STATE:
+                        monitoringMode = MonitoringMode.Reporting;
+                        break;
+                    case EVENT:
+                        monitoringMode = MonitoringMode.Reporting;
+                        break;
+                    default:
+                        monitoringMode = MonitoringMode.Reporting;
+                }
 
+                PlcSubscriptionHandle subHandle = null;
+                PlcResponseCode responseCode = PlcResponseCode.ACCESS_DENIED;
+                try {
+                    UaSubscription subscription = client.getSubscriptionManager().createSubscription(cycleTime).get();
+
+                    MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
+                        readValueId, monitoringMode, parameters);
+                    List<MonitoredItemCreateRequest> requestList = new LinkedList<>();
+                    requestList.add(request);
+                    OpcuaSubsriptionHandle subsriptionHandle = new OpcuaSubsriptionHandle(fieldName, clientHandle);
+                    BiConsumer<UaMonitoredItem, Integer> onItemCreated =
+                        (item, id) -> item.setValueConsumer(subsriptionHandle::onSubscriptionValue);
+
+                    List<UaMonitoredItem> items = subscription.createMonitoredItems(
+                        TimestampsToReturn.Both,
+                        requestList,
+                        onItemCreated
+                    ).get();
+
+                    subHandle = subsriptionHandle;
+                    responseCode = PlcResponseCode.OK;
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    logger.warn("Unable to subscribe Elements because of: {}", e.getMessage());
+                } catch (ExecutionException e) {
+                    logger.warn("Unable to subscribe Elements because of: {}", e.getMessage());
+                }
 
-                    return Pair.of(plcFieldName, new ResponseItem(responseCode, subHandle));
-                })
-                .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
-            return new DefaultPlcSubscriptionResponse(internalPlcSubscriptionRequest, responseItems);
+                responseItems.put(fieldName, new ResponseItem(responseCode, subHandle));
+            }
+            return new DefaultPlcSubscriptionResponse(subscriptionRequest, responseItems);
         });
 
         return future;
@@ -359,8 +358,7 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
 
     @Override
     public CompletableFuture<PlcUnsubscriptionResponse> unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest) {
-        InternalPlcUnsubscriptionRequest internalPlcUnsubscriptionRequest = checkInternal(unsubscriptionRequest, InternalPlcUnsubscriptionRequest.class);
-        internalPlcUnsubscriptionRequest.getInternalPlcSubscriptionHandles().forEach(o -> {
+/*        unsubscriptionRequest.getPlcSubscriptionHandles().forEach(o -> {
             OpcuaSubsriptionHandle opcSubHandle = (OpcuaSubsriptionHandle) o;
             try {
                 client.getSubscriptionManager().deleteSubscription(opcSubHandle.getClientHandle()).get();
@@ -370,17 +368,21 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
             } catch (ExecutionException e) {
                 logger.warn("Unable to unsubscribe Elements because of: {}", e.getMessage());
             }
-        });
+        });*/
 
         return null;
     }
 
     @Override
     public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> handles) {
-        List<PlcConsumerRegistration> unregisters = new LinkedList<>();
-        handles.forEach(plcSubscriptionHandle -> unregisters.add(plcSubscriptionHandle.register(consumer)));
+        List<PlcConsumerRegistration> registrations = new LinkedList<>();
+        // Register the current consumer for each of the given subscription handles
+        for (PlcSubscriptionHandle subscriptionHandle : handles) {
+            final PlcConsumerRegistration consumerRegistration = subscriptionHandle.register(consumer);
+            registrations.add(consumerRegistration);
+        }
 
-        return () -> unregisters.forEach(PlcConsumerRegistration::unregister);
+        return new DefaultPlcConsumerRegistration(this, consumer, handles.toArray(new PlcSubscriptionHandle[0]));
     }
 
     @Override
@@ -425,8 +427,7 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
 
 
             }
-            InternalPlcReadRequest internalPlcReadRequest = checkInternal(readRequest, InternalPlcReadRequest.class);
-            return new DefaultPlcReadResponse(internalPlcReadRequest, fields);
+            return new DefaultPlcReadResponse(readRequest, fields);
         });
 
         return future;
@@ -437,9 +438,6 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
         CompletableFuture<PlcWriteResponse> future;
         future = CompletableFuture.supplyAsync(() -> {
-
-            InternalPlcWriteRequest internalPlcWriteRequest = (InternalPlcWriteRequest) writeRequest;
-
             List<PlcField> writePLCValues = writeRequest.getFields();
             LinkedList<DataValue> values = new LinkedList<>();
             LinkedList<NodeId> ids = new LinkedList<>();
@@ -448,7 +446,7 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
             for (String fieldName : writeRequest.getFieldNames()) {
                 OpcuaField uaField = (OpcuaField) writeRequest.getField(fieldName);
                 NodeId idNode = generateNodeId(uaField);
-                Object valueObject = internalPlcWriteRequest.getPlcValue(fieldName).getObject();
+                Object valueObject = writeRequest.getPlcValue(fieldName).getObject();
                 // Added small work around for handling BigIntegers as input type for UInt64
                 if (valueObject instanceof BigInteger) valueObject = ulong((BigInteger) valueObject);
                 Variant var = new Variant(valueObject);
@@ -492,8 +490,7 @@ public class OpcuaTcpPlcConnection extends BaseOpcuaPlcConnection {
                 }
                 fieldResponse.put(names.get(counter), resultCode);
             }
-            InternalPlcWriteRequest internalPlcReadRequest = checkInternal(writeRequest, InternalPlcWriteRequest.class);
-            PlcWriteResponse response = new DefaultPlcWriteResponse(internalPlcReadRequest, fieldResponse);
+            PlcWriteResponse response = new DefaultPlcWriteResponse(writeRequest, fieldResponse);
             return response;
         });
 
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaPlcFieldHandler.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaPlcFieldHandler.java
index 91b6cdd..f6431ad 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaPlcFieldHandler.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaPlcFieldHandler.java
@@ -18,17 +18,13 @@
 */
 package org.apache.plc4x.java.opcua.protocol;
 
-
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
-
-import java.util.ArrayList;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
 /**
  */
-public class OpcuaPlcFieldHandler extends DefaultPlcFieldHandler {
+public class OpcuaPlcFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
@@ -38,17 +34,4 @@ public class OpcuaPlcFieldHandler extends DefaultPlcFieldHandler {
         throw new PlcInvalidFieldException(fieldQuery);
     }
 
-    @Override
-    public PlcValue encodeString(PlcField field, Object[] values) {
-        OpcuaField opcField = (OpcuaField) field;
-        ArrayList<String> resultSet = new ArrayList<>();
-        for (Object item : values) {
-            resultSet.add(item.toString());
-        }
-        if(resultSet.size() == 1) {
-            return new PlcSTRING(resultSet.get(0));
-        } else {
-            return new PlcList(resultSet);
-        }
-    }
 }
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubsriptionHandle.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubsriptionHandle.java
index 64bfe05..756f0cd 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubsriptionHandle.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubsriptionHandle.java
@@ -26,6 +26,7 @@ import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent;
 import org.apache.plc4x.java.opcua.connection.OpcuaTcpPlcConnection;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
 import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem;
 import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
 import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
@@ -41,6 +42,7 @@ import java.util.function.Consumer;
 /**
  */
 public class OpcuaSubsriptionHandle implements PlcSubscriptionHandle {
+
     private Set<Consumer<PlcSubscriptionEvent>> consumers = new HashSet<>();
     private String fieldName;
     private UInteger clientHandle;
@@ -83,7 +85,8 @@ public class OpcuaSubsriptionHandle implements PlcSubscriptionHandle {
     @Override
     public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer) {
         consumers.add(consumer);
-        return () -> consumers.remove(consumer);
+        return null;
+//        return () -> consumers.remove(consumer);
     }
 
 }
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualPLC4XOpcua.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualPLC4XOpcua.java
index 1ce540c..edc3614 100644
--- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualPLC4XOpcua.java
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualPLC4XOpcua.java
@@ -28,7 +28,7 @@ import org.apache.plc4x.java.opcua.connection.OpcuaTcpPlcConnection;
 import org.apache.plc4x.java.opcua.protocol.OpcuaField;
 import org.apache.plc4x.java.opcua.protocol.OpcuaPlcFieldHandler;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
 import org.eclipse.milo.examples.server.ExampleServer;
 
 import java.math.BigInteger;
@@ -135,7 +135,7 @@ public class ManualPLC4XOpcua {
                 opcuaConnection,
                 new LinkedHashMap<>(
                     Collections.singletonMap("field1",
-                        new SubscriptionPlcField(PlcSubscriptionType.CHANGE_OF_STATE, OpcuaField.of(STRING_IDENTIFIER), Duration.of(1, ChronoUnit.SECONDS)))
+                        new DefaultPlcSubscriptionField(PlcSubscriptionType.CHANGE_OF_STATE, OpcuaField.of(STRING_IDENTIFIER), Duration.of(1, ChronoUnit.SECONDS)))
                 )
             )).get();
 
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
index 18951e5..e30438d 100644
--- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
@@ -64,7 +64,7 @@ public class OpcuaPlcDriverTest {
     private static final String DATE_TIME_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/DateTime";
     private static final String DURATION_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Duration";
     private static final String GUID_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Guid";
-    private static final String LOCALICED_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/LocalizedText";
+    private static final String LOCALISED_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/LocalizedText";
     private static final String NODE_ID_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/NodeId";
     private static final String QUALIFIED_NAM_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/QualifiedName";
     private static final String UTC_TIME_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/UtcTime";
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
index b9e486a..26b39c6 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java
@@ -26,13 +26,13 @@ import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
 import org.apache.plc4x.java.s7.readwrite.optimizer.S7Optimizer;
 import org.apache.plc4x.java.s7.readwrite.protocol.S7ProtocolLogic;
 import org.apache.plc4x.java.s7.readwrite.field.S7PlcFieldHandler;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
 import org.apache.plc4x.java.spi.optimizer.BaseOptimizer;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 
 import java.util.function.Consumer;
 import java.util.function.ToIntFunction;
@@ -83,7 +83,7 @@ public class S7Driver extends GeneratedDriverBase<TPKTPacket> {
 
     @Override
     protected PlcValueHandler getValueHandler() {
-        return new S7ValueHandler();
+        return new IEC61131ValueHandler();
     }
 
     @Override
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
index ecff9b2..c34a621 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
@@ -33,6 +33,9 @@ import org.apache.plc4x.java.s7.readwrite.types.MemoryArea;
 import org.apache.plc4x.java.s7.readwrite.types.TransportSize;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -41,7 +44,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class S7Field implements PlcField {
+public class S7Field implements PlcField, XmlSerializable {
 
     //byteOffset theoretically can reach up to 2097151 ... see checkByteOffset() below --> 7digits
     private static final Pattern ADDRESS_PATTERN =
@@ -370,4 +373,36 @@ public class S7Field implements PlcField {
             ", numElements=" + numElements +
             '}';
     }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement(getClass().getSimpleName());
+        parent.appendChild(messageElement);
+
+        Element memoryAreaElement = doc.createElement("memoryArea");
+        memoryAreaElement.appendChild(doc.createTextNode(getMemoryArea().name()));
+        messageElement.appendChild(memoryAreaElement);
+
+        Element blockNumberElement = doc.createElement("blockNumber");
+        blockNumberElement.appendChild(doc.createTextNode(Integer.toString(getBlockNumber())));
+        messageElement.appendChild(blockNumberElement);
+
+        Element byteOffsetElement = doc.createElement("byteOffset");
+        byteOffsetElement.appendChild(doc.createTextNode(Integer.toString(getByteOffset())));
+        messageElement.appendChild(byteOffsetElement);
+
+        Element bitOffsetElement = doc.createElement("bitOffset");
+        bitOffsetElement.appendChild(doc.createTextNode(Integer.toString(getBitOffset())));
+        messageElement.appendChild(bitOffsetElement);
+
+        Element numElementsElement = doc.createElement("numElements");
+        numElementsElement.appendChild(doc.createTextNode(Integer.toString(getNumberOfElements())));
+        messageElement.appendChild(numElementsElement);
+
+        Element dataTypeElement = doc.createElement("dataType");
+        dataTypeElement.appendChild(doc.createTextNode(getDataType().name()));
+        messageElement.appendChild(dataTypeElement);
+    }
+
 }
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7PlcFieldHandler.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7PlcFieldHandler.java
index a542957..8c78cc7 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7PlcFieldHandler.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7PlcFieldHandler.java
@@ -19,23 +19,10 @@ under the License.
 package org.apache.plc4x.java.s7.readwrite.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.lang.reflect.InvocationTargetException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
-public class S7PlcFieldHandler extends DefaultPlcFieldHandler {
+public class S7PlcFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
@@ -45,55 +32,4 @@ public class S7PlcFieldHandler extends DefaultPlcFieldHandler {
         throw new PlcInvalidFieldException(fieldQuery);
     }
 
-    @Override
-    public PlcValue encodeTime(PlcField field, Object[] values) {
-        S7Field s7Field = (S7Field) field;
-        switch (s7Field.getDataType()) {
-            case TIME:
-                return internalEncodeTemporal(field, values);
-            default:
-                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
-        }
-    }
-
-    @Override
-    public PlcValue encodeDate(PlcField field, Object[] values) {
-        S7Field s7Field = (S7Field) field;
-        switch (s7Field.getDataType()) {
-            case DATE:
-                return internalEncodeTemporal(field, values);
-            default:
-                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
-        }
-    }
-
-    @Override
-    public PlcValue encodeDateTime(PlcField field, Object[] values) {
-        S7Field s7Field = (S7Field) field;
-        switch (s7Field.getDataType()) {
-            case DATE_AND_TIME:
-                return internalEncodeTemporal(field, values);
-            default:
-                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
-        }
-    }
-
-    private PlcValue internalEncodeTemporal(PlcField field, Object[] values) {
-        if(values.length > 1) {
-            return new PlcList(Arrays.asList(values));
-        }
-        S7Field s7Field = (S7Field) field;
-        switch (s7Field.getDataType()) {
-            case TIME:
-                return new PlcTime((LocalTime) values[0]);
-            case DATE:
-                return new PlcDate((LocalDate) values[0]);
-            case DATE_AND_TIME:
-                return new PlcDateTime((LocalDateTime) values[0]);
-            default:
-                throw new IllegalArgumentException(
-                    "Cannot assign temporal values to " + s7Field.getDataType().name() + " fields.");
-        }
-    }
-
 }
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7StringField.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7StringField.java
index bd128c6..eeab916 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7StringField.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7StringField.java
@@ -22,6 +22,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.plc4x.java.s7.readwrite.types.MemoryArea;
 import org.apache.plc4x.java.s7.readwrite.types.TransportSize;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 public class S7StringField extends S7Field {
 
@@ -40,4 +42,14 @@ public class S7StringField extends S7Field {
         return stringLength;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        super.xmlSerialize(parent);
+
+        Document doc = parent.getOwnerDocument();
+        Element byteOffsetElement = doc.createElement("byteOffset");
+        byteOffsetElement.appendChild(doc.createTextNode(Integer.toString(getByteOffset())));
+        parent.getFirstChild().appendChild(byteOffsetElement);
+    }
+
 }
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index 6d9d16d..403d325 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -29,11 +29,9 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcNull;
+import org.apache.plc4x.java.spi.values.PlcNull;
 import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.api.value.PlcValues;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
-import org.apache.plc4x.java.api.value.PlcValueHandler;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.s7.readwrite.*;
 import org.apache.plc4x.java.s7.readwrite.context.S7DriverContext;
 import org.apache.plc4x.java.s7.readwrite.field.S7StringField;
@@ -50,8 +48,6 @@ import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
 import org.slf4j.Logger;
@@ -183,11 +179,11 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
             null);
 
         // Just send a single response and chain it as Response
-        return toPlcReadResponse((InternalPlcReadRequest) readRequest, readInternal(s7MessageRequest));
+        return toPlcReadResponse(readRequest, readInternal(s7MessageRequest));
     }
 
     /** Maps the S7ReadResponse of a PlcReadRequest to a PlcReadResponse */
-    private CompletableFuture<PlcReadResponse> toPlcReadResponse(InternalPlcReadRequest readRequest, CompletableFuture<S7Message> response) {
+    private CompletableFuture<PlcReadResponse> toPlcReadResponse(PlcReadRequest readRequest, CompletableFuture<S7Message> response) {
         return response
             .thenApply(p -> {
                 try {
@@ -272,7 +268,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
             .check(p -> p.getTpduReference() == tpduId)
             .handle(p -> {
                 try {
-                    future.complete(((PlcWriteResponse) decodeWriteResponse(p, ((InternalPlcWriteRequest) writeRequest))));
+                    future.complete(((PlcWriteResponse) decodeWriteResponse(p, writeRequest)));
                 } catch (PlcProtocolException e) {
                     LOGGER.warn(String.format("Error sending 'write' message: '%s'", e.getMessage()), e);
                 }
@@ -358,7 +354,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
             }, null, (short) 0x0000, (short) 0x000F, COTPProtocolClass.CLASS_0);
     }
 
-    private PlcResponse decodeReadResponse(S7Message responseMessage, InternalPlcReadRequest plcReadRequest) throws PlcProtocolException {
+    private PlcResponse decodeReadResponse(S7Message responseMessage, PlcReadRequest plcReadRequest) throws PlcProtocolException {
         Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
         short errorClass;
         short errorCode;
@@ -429,7 +425,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
         return new DefaultPlcReadResponse(plcReadRequest, values);
     }
 
-    private PlcResponse decodeWriteResponse(S7Message responseMessage, InternalPlcWriteRequest plcWriteRequest) throws PlcProtocolException {
+    private PlcResponse decodeWriteResponse(S7Message responseMessage, PlcWriteRequest plcWriteRequest) throws PlcProtocolException {
         Map<String, PlcResponseCode> responses = new HashMap<>();
         short errorClass;
         short errorCode;
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/value/S7ValueHandler.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/value/S7ValueHandler.java
deleted file mode 100644
index 8193912..0000000
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/value/S7ValueHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.api.value;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
-import org.apache.plc4x.java.api.value.PlcValueHandler;
-
-import java.math.BigInteger;
-import java.math.BigDecimal;
-import java.nio.charset.StandardCharsets;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
-
-public abstract class S7ValueHandler extends IEC61131ValueHandler {
-
-    @Override
-    public PlcValue customDataType(PlcField field, Object value) {
-        switch (field.getPlcDataType().toUpperCase()) {
-            case "TIME":
-                return PlcBOOL.of(value);
-            case "DATE":
-                return PlcBYTE.of(value);
-            case "DATE_AND_TIME":
-                return PlcSINT.of(value);
-            default:
-                throw PlcUnsuppportedDataTypeException("Data Type " + field.getPlcDataType())
-                    + "Is not supported");
-        }
-    }
-}
diff --git a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedConnection.java b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedConnection.java
index 3028935..5e60169 100644
--- a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedConnection.java
+++ b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedConnection.java
@@ -28,6 +28,7 @@ import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
@@ -43,26 +44,19 @@ import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcSubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcUnsubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.PlcReader;
 import org.apache.plc4x.java.spi.messages.PlcSubscriber;
 import org.apache.plc4x.java.spi.messages.PlcWriter;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
 import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.InternalPlcConsumerRegistration;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 
 import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
@@ -79,7 +73,7 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
 
     private boolean connected = false;
 
-    private Map<InternalPlcSubscriptionHandle, InternalPlcConsumerRegistration> registrations = new ConcurrentHashMap<>();
+    private Map<PlcSubscriptionHandle, PlcConsumerRegistration> registrations = new ConcurrentHashMap<>();
 
     private Map<Integer, Consumer<PlcSubscriptionEvent>> consumerIdMap = new ConcurrentHashMap<>();
 
@@ -124,7 +118,7 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
 
     @Override
     public PlcWriteRequest.Builder writeRequestBuilder() {
-        return new DefaultPlcWriteRequest.Builder(this, new SimulatedFieldHandler());
+        return new DefaultPlcWriteRequest.Builder(this, new SimulatedFieldHandler(), new IEC61131ValueHandler());
     }
 
     @Override
@@ -139,10 +133,9 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
 
     @Override
     public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
-        InternalPlcReadRequest request = checkInternal(readRequest, InternalPlcReadRequest.class);
         Map<String, ResponseItem<PlcValue>> fields = new HashMap<>();
-        for (String fieldName : request.getFieldNames()) {
-            SimulatedField field = (SimulatedField) request.getField(fieldName);
+        for (String fieldName : readRequest.getFieldNames()) {
+            SimulatedField field = (SimulatedField) readRequest.getField(fieldName);
             Optional<PlcValue> valueOptional = device.get(field);
             ResponseItem<PlcValue> fieldPair;
             boolean present = valueOptional.isPresent();
@@ -151,21 +144,20 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
                 : new ResponseItem<>(PlcResponseCode.NOT_FOUND, null);
             fields.put(fieldName, fieldPair);
         }
-        PlcReadResponse response = new DefaultPlcReadResponse(request, fields);
+        PlcReadResponse response = new DefaultPlcReadResponse(readRequest, fields);
         return CompletableFuture.completedFuture(response);
     }
 
     @Override
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
-        InternalPlcWriteRequest request = checkInternal(writeRequest, InternalPlcWriteRequest.class);
         Map<String, PlcResponseCode> fields = new HashMap<>();
-        for (String fieldName : request.getFieldNames()) {
-            SimulatedField field = (SimulatedField) request.getField(fieldName);
-            PlcValue value = request.getPlcValue(fieldName);
+        for (String fieldName : writeRequest.getFieldNames()) {
+            SimulatedField field = (SimulatedField) writeRequest.getField(fieldName);
+            PlcValue value = writeRequest.getPlcValue(fieldName);
             device.set(field, value);
             fields.put(fieldName, PlcResponseCode.OK);
         }
-        PlcWriteResponse response = new DefaultPlcWriteResponse(request, fields);
+        PlcWriteResponse response = new DefaultPlcWriteResponse(writeRequest, fields);
         return CompletableFuture.completedFuture(response);
     }
 
@@ -176,38 +168,36 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
 
     @Override
     public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
-        InternalPlcSubscriptionRequest request = checkInternal(subscriptionRequest, InternalPlcSubscriptionRequest.class);
-        Map<String, SubscriptionPlcField> subscriptionPlcFieldMap = request.getSubscriptionPlcFieldMap();
-
         Map<String, ResponseItem<PlcSubscriptionHandle>> values = new HashMap<>();
-        subscriptionPlcFieldMap.forEach((name, subscriptionPlcField) -> {
-            InternalPlcSubscriptionHandle handle = new DefaultPlcSubscriptionHandle(this);
+        subscriptionRequest.getFieldNames().forEach(name -> {
+            PlcSubscriptionHandle handle = new DefaultPlcSubscriptionHandle(this);
+            final PlcSubscriptionField subscriptionPlcField = subscriptionRequest.getField(name);
             switch (subscriptionPlcField.getPlcSubscriptionType()) {
                 case CYCLIC:
-                    device.addCyclicSubscription(dispatchSubscriptionEvent(name, handle), handle, (SimulatedField) subscriptionPlcField.getPlcField(), subscriptionPlcField.getDuration().orElseThrow(RuntimeException::new));
+                    device.addCyclicSubscription(dispatchSubscriptionEvent(name, handle), handle, subscriptionPlcField, subscriptionPlcField.getDuration().orElseThrow(RuntimeException::new));
                     break;
                 case CHANGE_OF_STATE:
-                    device.addChangeOfStateSubscription(dispatchSubscriptionEvent(name, handle), handle, (SimulatedField) subscriptionPlcField.getPlcField());
+                    device.addChangeOfStateSubscription(dispatchSubscriptionEvent(name, handle), handle, subscriptionPlcField);
                     break;
                 case EVENT:
-                    device.addEventSubscription(dispatchSubscriptionEvent(name, handle), handle, (SimulatedField) subscriptionPlcField.getPlcField());
+                    device.addEventSubscription(dispatchSubscriptionEvent(name, handle), handle, subscriptionPlcField);
                     break;
             }
             values.put(name, new ResponseItem<>(PlcResponseCode.OK, handle));
         });
 
-        PlcSubscriptionResponse response = new DefaultPlcSubscriptionResponse(request, values);
+        PlcSubscriptionResponse response = new DefaultPlcSubscriptionResponse(subscriptionRequest, values);
         return CompletableFuture.completedFuture(response);
     }
 
-    private Consumer<PlcValue> dispatchSubscriptionEvent(String name, InternalPlcSubscriptionHandle handle) {
+    private Consumer<PlcValue> dispatchSubscriptionEvent(String name, PlcSubscriptionHandle handle) {
         return plcValue -> {
-            InternalPlcConsumerRegistration plcConsumerRegistration = registrations.get(handle);
+            PlcConsumerRegistration plcConsumerRegistration = registrations.get(handle);
             if (plcConsumerRegistration == null) {
                 return;
             }
-            int consumerHash = plcConsumerRegistration.getConsumerHash();
-            Consumer<PlcSubscriptionEvent> consumer = consumerIdMap.get(consumerHash);
+            int consumerId = ((DefaultPlcConsumerRegistration) plcConsumerRegistration).getConsumerId();
+            Consumer<PlcSubscriptionEvent> consumer = consumerIdMap.get(consumerId);
             if (consumer == null) {
                 return;
             }
@@ -218,36 +208,34 @@ public class SimulatedConnection extends AbstractPlcConnection implements PlcRea
 
     @Override
     public CompletableFuture<PlcUnsubscriptionResponse> unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest) {
-        InternalPlcUnsubscriptionRequest request = checkInternal(unsubscriptionRequest, InternalPlcUnsubscriptionRequest.class);
-
-        device.removeHandles(request.getInternalPlcSubscriptionHandles());
+        device.removeHandles(unsubscriptionRequest.getSubscriptionHandles());
 
-        PlcUnsubscriptionResponse response = new DefaultPlcUnsubscriptionResponse(request);
+        PlcUnsubscriptionResponse response = new DefaultPlcUnsubscriptionResponse(unsubscriptionRequest);
         return CompletableFuture.completedFuture(response);
     }
 
     @Override
     public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> handles) {
-        InternalPlcConsumerRegistration plcConsumerRegistration = new DefaultPlcConsumerRegistration(this, consumer, handles.toArray(new InternalPlcSubscriptionHandle[0]));
+        PlcConsumerRegistration plcConsumerRegistration = new DefaultPlcConsumerRegistration(this, consumer, handles.toArray(new PlcSubscriptionHandle[0]));
         handles.stream()
-            .map(InternalPlcSubscriptionHandle.class::cast)
+            .map(PlcSubscriptionHandle.class::cast)
             .forEach(handle -> registrations.put(handle, plcConsumerRegistration));
-        consumerIdMap.put(plcConsumerRegistration.getConsumerHash(), consumer);
+        consumerIdMap.put(plcConsumerRegistration.getConsumerId(), consumer);
         return plcConsumerRegistration;
     }
 
     @Override
     public void unregister(PlcConsumerRegistration registration) {
-        Iterator<Map.Entry<InternalPlcSubscriptionHandle, InternalPlcConsumerRegistration>> entryIterator = registrations.entrySet().iterator();
+        Iterator<Map.Entry<PlcSubscriptionHandle, PlcConsumerRegistration>> entryIterator = registrations.entrySet().iterator();
         while (entryIterator.hasNext()) {
-            Map.Entry<InternalPlcSubscriptionHandle, InternalPlcConsumerRegistration> entry = entryIterator.next();
+            Map.Entry<PlcSubscriptionHandle, PlcConsumerRegistration> entry = entryIterator.next();
             if (!entry.getValue().equals(registration)) {
                 continue;
             }
-            InternalPlcConsumerRegistration value = entry.getValue();
-            int consumerHash = value.getConsumerHash();
-            consumerIdMap.remove(consumerHash);
-            device.removeHandles(value.getAssociatedHandles());
+            PlcConsumerRegistration consumerRegistration = entry.getValue();
+            int consumerId = consumerRegistration.getConsumerId();
+            consumerIdMap.remove(consumerId);
+            device.removeHandles(consumerRegistration.getSubscriptionHandles());
             entryIterator.remove();
         }
     }
diff --git a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedDevice.java b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedDevice.java
index ec507f1..a8ed034 100644
--- a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedDevice.java
+++ b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/SimulatedDevice.java
@@ -19,13 +19,12 @@
 package org.apache.plc4x.java.simulated.connection;
 
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.api.value.PlcValues;
-import org.apache.plc4x.java.api.value.IEC61131ValueHandler;
-import org.apache.plc4x.java.api.value.PlcValueHandler;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.simulated.field.SimulatedField;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
 
 import java.time.Duration;
 import java.util.*;
@@ -141,9 +140,9 @@ public class SimulatedDevice {
         return name;
     }
 
-    public void addCyclicSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, SimulatedField plcField, Duration duration) {
+    public void addCyclicSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, PlcSubscriptionField plcField, Duration duration) {
         ScheduledFuture<?> scheduledFuture = scheduler.scheduleAtFixedRate(() -> {
-            PlcValue baseDefaultPlcValue = state.get(plcField);
+            PlcValue baseDefaultPlcValue = state.get(((DefaultPlcSubscriptionField) plcField).getPlcField());
             if (baseDefaultPlcValue == null) {
                 return;
             }
@@ -152,14 +151,14 @@ public class SimulatedDevice {
         cyclicSubscriptions.put(handle, scheduledFuture);
     }
 
-    public void addChangeOfStateSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, SimulatedField plcField) {
-        changeOfStateSubscriptions.put(handle, Pair.of(plcField, consumer));
+    public void addChangeOfStateSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, PlcSubscriptionField plcField) {
+        changeOfStateSubscriptions.put(handle, Pair.of((SimulatedField) ((DefaultPlcSubscriptionField) plcField).getPlcField(), consumer));
     }
 
-    public void addEventSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, SimulatedField plcField) {
+    public void addEventSubscription(Consumer<PlcValue> consumer, PlcSubscriptionHandle handle, PlcSubscriptionField plcField) {
         Future<?> submit = pool.submit(() -> {
             while (!Thread.currentThread().isInterrupted()) {
-                PlcValue baseDefaultPlcValue = state.get(plcField);
+                PlcValue baseDefaultPlcValue = state.get(((DefaultPlcSubscriptionField) plcField).getPlcField());
                 if (baseDefaultPlcValue == null) {
                     continue;
                 }
@@ -176,7 +175,7 @@ public class SimulatedDevice {
         eventSubscriptions.put(handle, submit);
     }
 
-    public void removeHandles(Collection<? extends InternalPlcSubscriptionHandle> internalPlcSubscriptionHandles) {
+    public void removeHandles(Collection<? extends PlcSubscriptionHandle> internalPlcSubscriptionHandles) {
         internalPlcSubscriptionHandles.forEach(handle -> {
             ScheduledFuture<?> remove = cyclicSubscriptions.remove(handle);
             if (remove == null) {
diff --git a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/field/SimulatedFieldHandler.java b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/field/SimulatedFieldHandler.java
index 86545a4..2d42a4a 100644
--- a/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/field/SimulatedFieldHandler.java
+++ b/plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/field/SimulatedFieldHandler.java
@@ -20,17 +20,10 @@
 package org.apache.plc4x.java.simulated.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Arrays;
-
-public class SimulatedFieldHandler extends DefaultPlcFieldHandler {
+public class SimulatedFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) {
@@ -40,56 +33,4 @@ public class SimulatedFieldHandler extends DefaultPlcFieldHandler {
         throw new PlcInvalidFieldException(fieldQuery);
     }
 
-    @Override
-    public PlcValue encodeString(PlcField field, Object[] values) {
-        SimulatedField testField = (SimulatedField) field;
-        if (testField.getDataType() == String.class) {
-            if(values.length == 1) {
-                return new PlcSTRING((String) values[0]);
-            } else {
-                return new PlcList(Arrays.asList(values));
-            }
-        }
-        throw new PlcRuntimeException("Invalid encoder for type " + testField.getDataType().getName());
-    }
-
-    @Override
-    public PlcValue encodeTime(PlcField field, Object[] values) {
-        SimulatedField testField = (SimulatedField) field;
-        if (testField.getDataType() == LocalTime.class) {
-            if(values.length == 1) {
-                return new PlcTime((LocalTime) values[0]);
-            } else {
-                return new PlcList(Arrays.asList(values));
-            }
-        }
-        throw new PlcRuntimeException("Invalid encoder for type " + testField.getDataType().getName());
-    }
-
-    @Override
-    public PlcValue encodeDate(PlcField field, Object[] values) {
-        SimulatedField testField = (SimulatedField) field;
-        if (testField.getDataType() == LocalDate.class) {
-            if(values.length == 1) {
-                return new PlcDate((LocalDate) values[0]);
-            } else {
-                return new PlcList(Arrays.asList(values));
-            }
-        }
-        throw new PlcRuntimeException("Invalid encoder for type " + testField.getDataType().getName());
-    }
-
-    @Override
-    public PlcValue encodeDateTime(PlcField field, Object[] values) {
-        SimulatedField testField = (SimulatedField) field;
-        if (testField.getDataType() == LocalDateTime.class) {
-            if(values.length == 1) {
-                return new PlcDateTime((LocalDateTime) values[0]);
-            } else {
-                return new PlcList(Arrays.asList(values));
-            }
-        }
-        throw new PlcRuntimeException("Invalid encoder for type " + testField.getDataType().getName());
-    }
-
 }
diff --git a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedConnectionTest.java b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedConnectionTest.java
index 8defd2c..0893d62 100644
--- a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedConnectionTest.java
+++ b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedConnectionTest.java
@@ -22,7 +22,6 @@ package org.apache.plc4x.java.simulated.connection;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
 import org.assertj.core.api.WithAssertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -121,7 +120,7 @@ class SimulatedConnectionTest implements WithAssertions {
         @Test
         void unsubscribe() throws Exception {
             PlcUnsubscriptionRequest plcUnsubscriptionRequest = SUT.unsubscriptionRequestBuilder()
-                .addHandles(mock(InternalPlcSubscriptionHandle.class))
+                .addHandles(mock(PlcSubscriptionHandle.class))
                 .build();
 
             CompletableFuture<PlcUnsubscriptionResponse> unsubscribe = SUT.unsubscribe(plcUnsubscriptionRequest);
@@ -153,21 +152,23 @@ class SimulatedConnectionTest implements WithAssertions {
 
         @Test
         void subscription() throws Exception {
+            // Initialize the addresses
             PlcWriteRequest plcWriteRequest = SUT.writeRequestBuilder()
                 .addItem("cyclic", "STATE/cyclic:STRING", "initialcyclic")
                 .addItem("state", "STATE/state:STRING", "initialstate")
                 .addItem("event", "STATE/event:STRING", "initialevent")
                 .build();
-
             SUT.write(plcWriteRequest).get(1, TimeUnit.SECONDS);
 
+            // Subscribe for the addresses
             PlcSubscriptionRequest plcSubscriptionRequest = SUT.subscriptionRequestBuilder()
                 .addCyclicField("cyclic", "STATE/cyclic:String", Duration.ofSeconds(1))
                 .addChangeOfStateField("state", "STATE/state:String")
                 .addEventField("event", "STATE/event:String")
                 .build();
-
             PlcSubscriptionResponse plcSubscriptionResponse = SUT.subscribe(plcSubscriptionRequest).get(1, TimeUnit.SECONDS);
+
+            // Register some handlers for the subscriptions that simply put the messages in a queue.
             Queue<PlcSubscriptionEvent> cyclicQueue = new ConcurrentLinkedQueue<>();
             PlcConsumerRegistration cyclicRegistration = plcSubscriptionResponse.getSubscriptionHandle("cyclic").register(cyclicQueue::add);
             Queue<PlcSubscriptionEvent> stateQueue = new ConcurrentLinkedQueue<>();
@@ -175,28 +176,35 @@ class SimulatedConnectionTest implements WithAssertions {
             Queue<PlcSubscriptionEvent> eventQueue = new ConcurrentLinkedQueue<>();
             PlcConsumerRegistration eventRegistration = plcSubscriptionResponse.getSubscriptionHandle("event").register(eventQueue::add);
             assertThat(plcSubscriptionResponse.getFieldNames()).isNotEmpty();
+
+            // Give the system some time to do stuff
             TimeUnit.SECONDS.sleep(10);
 
+            // Write something to the addresses in order to trigger a value-change event
             PlcWriteRequest plcWriteRequest2 = SUT.writeRequestBuilder()
                 .addItem("cyclic", "STATE/cyclic:STRING", "changedcyclic")
                 .addItem("state", "STATE/state:STRING", "changedstate")
                 .addItem("event", "STATE/event:STRING", "changedevent")
                 .build();
-
             SUT.write(plcWriteRequest2).get(1, TimeUnit.SECONDS);
+
+            // Unregister all consumers
             cyclicRegistration.unregister();
             stateRegistration.unregister();
             eventRegistration.unregister();
 
+            // The cyclic queue should not be empty as it had 10 seconds to get a value once per second
             assertThat(cyclicQueue).isNotEmpty();
-            cyclicQueue.forEach(plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("cyclic")
-            );
+            cyclicQueue.forEach(
+                plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("cyclic"));
+            // The state change queue should also not be empty as we forced an update with the second write
             assertThat(stateQueue).isNotEmpty();
-            stateQueue.forEach(plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("state")
-            );
+            stateQueue.forEach(
+                plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("state"));
+            // No idea, why this should not be empty
             assertThat(eventQueue).isNotEmpty();
-            eventQueue.forEach(plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("event")
-            );
+            eventQueue.forEach(
+                plcSubscriptionEvent -> assertThat(plcSubscriptionEvent.getFieldNames()).containsOnly("event"));
         }
     }
 
diff --git a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedDeviceTest.java b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedDeviceTest.java
index 268660d..162d470 100644
--- a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedDeviceTest.java
+++ b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/connection/SimulatedDeviceTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.plc4x.java.simulated.connection;
 
-import org.apache.plc4x.java.api.value.PlcLINT;
+import org.apache.plc4x.java.spi.values.PlcLINT;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.simulated.field.SimulatedField;
 import org.junit.jupiter.api.Test;
diff --git a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/field/SimularedFieldHandlerTest.java b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/field/SimularedFieldHandlerTest.java
index 983fa26..75a4716 100644
--- a/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/field/SimularedFieldHandlerTest.java
+++ b/plc4j/drivers/simulated/src/test/java/org/apache/plc4x/java/simulated/field/SimularedFieldHandlerTest.java
@@ -47,7 +47,7 @@ class SimularedFieldHandlerTest implements WithAssertions {
         assertThat(SUT.createField("STATE/bar:INTEGER")).isNotNull();
     }
 
-    @Test
+    /*@Test
     void encodeBoolean() {
         assertThat(SUT.encodeBoolean(plcField, new Boolean[0])).isNotNull();
     }
@@ -122,6 +122,6 @@ class SimularedFieldHandlerTest implements WithAssertions {
     void encodeDateTime() {
         when(plcField.getDataType()).thenReturn((Class) LocalDateTime.class);
         assertThat(SUT.encodeDateTime(plcField, new LocalDateTime[0])).isNotNull();
-    }
+    }*/
 
 }
diff --git a/plc4j/examples/dummy-driver/src/main/java/org/apache/plc4x/java/examples/dummydriver/connection/DummyConnection.java b/plc4j/examples/dummy-driver/src/main/java/org/apache/plc4x/java/examples/dummydriver/connection/DummyConnection.java
index 492c720..c5fec41 100644
--- a/plc4j/examples/dummy-driver/src/main/java/org/apache/plc4x/java/examples/dummydriver/connection/DummyConnection.java
+++ b/plc4j/examples/dummy-driver/src/main/java/org/apache/plc4x/java/examples/dummydriver/connection/DummyConnection.java
@@ -26,10 +26,8 @@ import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.spi.connection.NettyPlcConnection;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.InternalPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteResponse;
 import org.apache.plc4x.java.spi.messages.PlcReader;
 import org.apache.plc4x.java.spi.messages.PlcRequestContainer;
 import org.apache.plc4x.java.spi.messages.PlcWriter;
diff --git a/plc4j/examples/hello-webapp/webapp/src/main/java/org/apache/plc4x/examples/watertank/service/WaterTankService.java b/plc4j/examples/hello-webapp/webapp/src/main/java/org/apache/plc4x/examples/watertank/service/WaterTankService.java
index e013216..9bb2068 100644
--- a/plc4j/examples/hello-webapp/webapp/src/main/java/org/apache/plc4x/examples/watertank/service/WaterTankService.java
+++ b/plc4j/examples/hello-webapp/webapp/src/main/java/org/apache/plc4x/examples/watertank/service/WaterTankService.java
@@ -32,7 +32,7 @@ import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcINT;
+import org.apache.plc4x.java.spi.values.PlcINT;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionEvent;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
diff --git a/plc4j/examples/hello-webservice/src/main/java/org/apache/plc4x/java/examples/hellowebservice/HelloWebservice.java b/plc4j/examples/hello-webservice/src/main/java/org/apache/plc4x/java/examples/hellowebservice/HelloWebservice.java
index f0a670f..978b7c5 100644
--- a/plc4j/examples/hello-webservice/src/main/java/org/apache/plc4x/java/examples/hellowebservice/HelloWebservice.java
+++ b/plc4j/examples/hello-webservice/src/main/java/org/apache/plc4x/java/examples/hellowebservice/HelloWebservice.java
@@ -33,7 +33,7 @@ import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.api.value.PlcStruct;
+import org.apache.plc4x.java.api.value.PlcValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -133,7 +133,7 @@ public class HelloWebservice {
             // Iterate over all the fields in this event and then simply output
             // them to the console in a JSON format.
             for (String fieldName : plcSubscriptionEvent.getFieldNames()) {
-                final PlcStruct plcValue = (PlcStruct) plcSubscriptionEvent.getPlcValue(fieldName);
+                final PlcValue plcValue = plcSubscriptionEvent.getPlcValue(fieldName);
 
                 // Create a JSON object that fits the structure of my remote webservice.
                 JsonObject output = new JsonObject();
diff --git a/plc4j/integrations/apache-camel/src/test/java/org/apache/plc4x/camel/MockDriver.java b/plc4j/integrations/apache-camel/src/test/java/org/apache/plc4x/camel/MockDriver.java
index 1e7b8f1..9ae9b19 100644
--- a/plc4j/integrations/apache-camel/src/test/java/org/apache/plc4x/camel/MockDriver.java
+++ b/plc4j/integrations/apache-camel/src/test/java/org/apache/plc4x/camel/MockDriver.java
@@ -23,7 +23,6 @@ import org.apache.plc4x.java.api.authentication.PlcAuthentication;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcSubscriptionRequest;
 import org.apache.plc4x.java.spi.messages.PlcSubscriber;
 import org.apache.plc4x.java.api.PlcDriver;
 import org.slf4j.Logger;
@@ -88,7 +87,7 @@ public class MockDriver implements PlcDriver {
                         mock(PlcSubscriptionHandle.class, RETURNS_DEEP_STUBS), PlcResponseCode.OK);
                 }).collect(Collectors.toList());
             PlcSubscriptionResponse response = new PlcSubscriptionResponse(subscriptionRequest, responseItems);*/
-            PlcSubscriptionResponse response = new DefaultPlcSubscriptionResponse(mock(InternalPlcSubscriptionRequest.class), new HashMap<>());
+            PlcSubscriptionResponse response = new DefaultPlcSubscriptionResponse(mock(PlcSubscriptionRequest.class), new HashMap<>());
             CompletableFuture<PlcSubscriptionResponse> responseFuture = new CompletableFuture<>();
             responseFuture.complete(response);
             return responseFuture;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/AbstractPlcConnection.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/AbstractPlcConnection.java
index 09cb882..b4ff5ba 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/AbstractPlcConnection.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/AbstractPlcConnection.java
@@ -21,15 +21,7 @@ package org.apache.plc4x.java.spi.connection;
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedOperationException;
-import org.apache.plc4x.java.api.messages.PlcReadRequest;
-import org.apache.plc4x.java.api.messages.PlcReadResponse;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse;
-import org.apache.plc4x.java.api.messages.PlcWriteRequest;
-import org.apache.plc4x.java.api.messages.PlcWriteResponse;
+import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.metadata.PlcConnectionMetadata;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
@@ -38,7 +30,6 @@ import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcMessage;
 import org.apache.plc4x.java.spi.messages.PlcReader;
 import org.apache.plc4x.java.spi.messages.PlcSubscriber;
 import org.apache.plc4x.java.spi.messages.PlcWriter;
@@ -47,7 +38,6 @@ import org.apache.plc4x.java.api.value.PlcValueHandler;
 
 
 import java.util.Collection;
-import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
 
@@ -197,21 +187,4 @@ public abstract class AbstractPlcConnection implements PlcConnection, PlcConnect
         throw new NotImplementedException("");
     }
 
-    /**
-     * Can be used to check and cast a parameter to its required internal type (can be used for general type checking too).
-     *
-     * @param o     the object to be checked against target {@code clazz}.
-     * @param clazz the expected {@code clazz}.
-     * @param <T>   the type of the expected {@code clazz}.
-     * @return the cast type of {@code clazz}.
-     */
-    protected <T extends InternalPlcMessage> T checkInternal(Object o, Class<T> clazz) {
-        Objects.requireNonNull(o);
-        Objects.requireNonNull(clazz);
-        if (!clazz.isInstance(o)) {
-            throw new IllegalArgumentException("illegal type " + o.getClass() + ". Expected " + clazz);
-        }
-        return clazz.cast(o);
-    }
-
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ChannelFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ChannelFactory.java
index 82d0b1f..d648c17 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ChannelFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/ChannelFactory.java
@@ -34,6 +34,4 @@ public interface ChannelFactory {
         // Intentionally do Nothing
     }
 
-    //void ping() throws PlcException;
-
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultNettyPlcConnection.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultNettyPlcConnection.java
index 292c458..3a718a6 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultNettyPlcConnection.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultNettyPlcConnection.java
@@ -112,21 +112,6 @@ public class DefaultNettyPlcConnection extends AbstractPlcConnection implements
         }
     }
 
-    /*@Override
-    public CompletableFuture<Void> ping() {
-        CompletableFuture<Void> future = new CompletableFuture<>();
-        try {
-            // Relay the actual pinging to the channel factory ...
-            channelFactory.ping();
-            // If we got here, the ping was successful.
-            future.complete(null);
-        } catch (PlcException e) {
-            // If we got here, something went wrong.
-            future.completeExceptionally(e);
-        }
-        return future;
-    }*/
-
     @Override
     public void close() throws PlcConnectionException {
         // TODO call protocols close method
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultPlcFieldHandler.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultPlcFieldHandler.java
deleted file mode 100644
index 03deb74..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/DefaultPlcFieldHandler.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.connection;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.*;
-
-import java.math.BigInteger;
-import java.math.BigDecimal;
-import java.nio.charset.StandardCharsets;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Base Implementation of {@link PlcFieldHandler} which throws a {@link PlcRuntimeException} for all
- * encodeXXX methods.
- */
-public abstract class DefaultPlcFieldHandler implements PlcFieldHandler {
-
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
index f07b88a..3b65f15 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
@@ -30,7 +30,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.SocketAddress;
-import java.util.Properties;
 
 /**
  * Adapter with sensible defaults for a Netty Based Channel Factory.
@@ -41,13 +40,11 @@ import java.util.Properties;
 public abstract class NettyChannelFactory implements ChannelFactory {
 
     private static final Logger logger = LoggerFactory.getLogger(NettyChannelFactory.class);
-    private static final int PING_TIMEOUT_MS = 1_000;
 
     /**
      * TODO should be removed together with the Constructor.
      */
     private SocketAddress address;
-    private Properties properties;
 
     public NettyChannelFactory(SocketAddress address) {
         this.address = address;
@@ -126,50 +123,9 @@ public abstract class NettyChannelFactory implements ChannelFactory {
             }
 
             return channel;
-/*        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new PlcConnectionException("Error creating channel.", e);*/
         } catch (Exception e) {
             throw new PlcConnectionException("Error creating channel.", e);
         }
     }
 
-    // TODO do we want to keep this like that?
-    /*@Override
-    public void ping() throws PlcException {
-        // TODO: Replace this check with a more accurate one ...
-        InetSocketAddress address = new InetSocketAddress(getAddress(), getPort());
-        try (Socket s = new Socket()) {
-            s.connect(address, PING_TIMEOUT_MS);
-            // TODO keep the address for a (timely) next request???
-            s.setReuseAddress(true);
-        } catch (Exception e) {
-            throw new PlcConnectionException("Unable to ping remote host");
-        }
-    }
-
-    public Properties getProperties() {
-        // Null Safety for older implementations
-        if (properties == null) {
-            return new Properties();
-        }
-        return properties;
-    }
-
-    public void setProperties(Properties properties) {
-        this.properties = properties;
-    }
-
-    protected String getProperty(String key) {
-        return ((String) getProperties().get(key));
-    }
-
-    protected boolean hasProperty(String key) {
-        return getProperties().contains(key);
-    }
-
-    protected String getPropertyOrDefault(String key, String defaultValue) {
-        return getProperties().getProperty(key, defaultValue);
-    }*/
-
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/PlcFieldHandler.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/PlcFieldHandler.java
index 551692e..e947615 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/PlcFieldHandler.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/PlcFieldHandler.java
@@ -18,15 +18,13 @@
  */
 package org.apache.plc4x.java.spi.connection;
 
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcValue;
 
 /**
  * Field Handler which handles the parsing of string to {@link PlcField} and the encoding of retrieved plc values.
  */
 public interface PlcFieldHandler {
 
-    PlcField createField(String fieldQuery) throws PlcInvalidFieldException;
+    PlcField createField(String fieldQuery);
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
index 4da2338..54b1747 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/SingleProtocolStackConfigurer.java
@@ -29,7 +29,6 @@ import org.apache.plc4x.java.spi.Plc4xNettyWrapper;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.context.DriverContext;
-import org.apache.plc4x.java.spi.exceptions.InternalPlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.Message;
 import org.apache.plc4x.java.spi.generation.MessageIO;
 
@@ -102,7 +101,7 @@ public class SingleProtocolStackConfigurer<BASE_PACKET_CLASS extends Message> im
             }
             return clazz.getDeclaredConstructor(parameterTypes).newInstance(args);
         } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException  e) {
-            throw new InternalPlcRuntimeException("Error creating instance of class " + clazz.getName());
+            throw new PlcRuntimeException("Error creating instance of class " + clazz.getName());
         }
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/exceptions/InternalPlcRuntimeException.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/exceptions/InternalPlcRuntimeException.java
deleted file mode 100644
index 4c00e6d..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/exceptions/InternalPlcRuntimeException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-package org.apache.plc4x.java.spi.exceptions;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-
-public class InternalPlcRuntimeException extends PlcRuntimeException {
-
-    public InternalPlcRuntimeException(String message) {
-        super(message);
-    }
-
-    public InternalPlcRuntimeException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public InternalPlcRuntimeException(Throwable cause) {
-        super(cause);
-    }
-
-    public InternalPlcRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryRequest.java
deleted file mode 100644
index f29fa31..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryRequest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.messages.PlcResponse;
-
-import java.util.concurrent.CompletableFuture;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcProprietaryRequest<REQUEST> implements InternalPlcProprietaryRequest<REQUEST> {
-
-    @Override
-    @JsonIgnore
-    public CompletableFuture<PlcResponse> execute() {
-        throw new PlcRuntimeException("not supported"); // TODO: figure out what to do with this
-    }
-
-    private REQUEST proprietaryRequest;
-
-    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcProprietaryRequest(@JsonProperty("proprietaryRequest") REQUEST proprietaryRequest) {
-        this.proprietaryRequest = proprietaryRequest;
-    }
-
-    @Override
-    public REQUEST getProprietaryRequest() {
-        return proprietaryRequest;
-    }
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryResponse.java
deleted file mode 100644
index 5d5a167..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcProprietaryResponse.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcProprietaryResponse<RESPONSE> implements InternalPlcProprietaryResponse<RESPONSE> {
-
-    private final InternalPlcProprietaryRequest plcProprietaryRequest;
-
-    private final RESPONSE proprietaryResponse;
-
-    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcProprietaryResponse(@JsonProperty("plcProprietaryRequest") InternalPlcProprietaryRequest plcProprietaryRequest,
-                                         @JsonProperty("proprietaryResponse") RESPONSE proprietaryResponse) {
-        this.plcProprietaryRequest = plcProprietaryRequest;
-        this.proprietaryResponse = proprietaryResponse;
-    }
-
-    @Override
-    public RESPONSE getResponse() {
-        return proprietaryResponse;
-    }
-
-    @Override
-    public InternalPlcProprietaryRequest getRequest() {
-        return plcProprietaryRequest;
-    }
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
index 1acbfb3..ace32d3 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
@@ -21,10 +21,14 @@ package org.apache.plc4x.java.spi.messages;
 import com.fasterxml.jackson.annotation.*;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcFieldRequest;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -37,7 +41,7 @@ import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcReadRequest implements InternalPlcReadRequest, InternalPlcFieldRequest {
+public class DefaultPlcReadRequest implements PlcReadRequest, PlcFieldRequest, XmlSerializable {
 
     private final PlcReader reader;
     private LinkedHashMap<String, PlcField> fields;
@@ -80,7 +84,6 @@ public class DefaultPlcReadRequest implements InternalPlcReadRequest, InternalPl
         return new LinkedList<>(fields.values());
     }
 
-    @Override
     @JsonIgnore
     public List<Pair<String, PlcField>> getNamedFields() {
         return fields.entrySet()
@@ -104,6 +107,25 @@ public class DefaultPlcReadRequest implements InternalPlcReadRequest, InternalPl
         return fields;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement("PlcReadRequest");
+        Element fieldsElement = doc.createElement("fields");
+        messageElement.appendChild(fieldsElement);
+        for (Map.Entry<String, PlcField> fieldEntry : fields.entrySet()) {
+            String fieldName = fieldEntry.getKey();
+            Element fieldNameElement = doc.createElement(fieldName);
+            fieldsElement.appendChild(fieldNameElement);
+            PlcField field = fieldEntry.getValue();
+            if(!(field instanceof XmlSerializable)) {
+                throw new RuntimeException("Error serializing. Field doesn't implement XmlSerializable");
+            }
+            ((XmlSerializable) field).xmlSerialize(fieldNameElement);
+        }
+        parent.appendChild(messageElement);
+    }
+
     public static class Builder implements PlcReadRequest.Builder {
 
         private final PlcReader reader;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
index e048cf4..a59d985 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
@@ -21,13 +21,17 @@ package org.apache.plc4x.java.spi.messages;
 import com.fasterxml.jackson.annotation.*;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcList;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.apache.plc4x.java.spi.values.PlcList;
 import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.api.value.PlcValues;
+import org.apache.plc4x.java.spi.values.PlcValues;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -39,20 +43,20 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadResponse {
+public class DefaultPlcReadResponse implements PlcReadResponse, XmlSerializable {
 
-    private final InternalPlcReadRequest request;
+    private final PlcReadRequest request;
     private final Map<String, ResponseItem<PlcValue>> values;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcReadResponse(@JsonProperty("request") InternalPlcReadRequest request,
+    public DefaultPlcReadResponse(@JsonProperty("request") PlcReadRequest request,
                                   @JsonProperty("values") Map<String, ResponseItem<PlcValue>> values) {
         this.request = request;
         this.values = values;
     }
 
     @Override
-    public InternalPlcReadRequest getRequest() {
+    public PlcReadRequest getRequest() {
         return request;
     }
 
@@ -102,7 +106,6 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         return values.get(name).getCode();
     }
 
-    @Override
     @JsonIgnore
     public Map<String, ResponseItem<PlcValue>> getValues() {
         return values;
@@ -708,4 +711,24 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         return field;
     }
 
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement("PlcReadResponse");
+        if(request instanceof XmlSerializable) {
+            ((XmlSerializable) request).xmlSerialize(messageElement);
+        }
+        Element valuesElement = doc.createElement("values");
+        messageElement.appendChild(valuesElement);
+        for (Map.Entry<String, ResponseItem<PlcValue>> valueEntry : values.entrySet()) {
+            String fieldName = valueEntry.getKey();
+            Element fieldNameElement = doc.createElement(fieldName);
+            valuesElement.appendChild(fieldNameElement);
+            ResponseItem<PlcValue> valueResponse = valueEntry.getValue();
+            valueResponse.xmlSerialize(fieldNameElement);
+        }
+        parent.appendChild(messageElement);
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionEvent.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionEvent.java
index 23a3864..ffa735b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionEvent.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionEvent.java
@@ -23,9 +23,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 
@@ -34,7 +33,7 @@ import java.util.Collection;
 import java.util.Map;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcSubscriptionEvent extends DefaultPlcReadResponse implements InternalPlcSubscriptionEvent {
+public class DefaultPlcSubscriptionEvent extends DefaultPlcReadResponse implements PlcSubscriptionEvent {
 
     public final Instant timestamp;
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionRequest.java
index f4ba364..95d3470 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionRequest.java
@@ -27,9 +27,12 @@ import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.types.PlcSubscriptionType;
 import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
+import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
 import java.time.Duration;
 import java.util.*;
@@ -37,15 +40,15 @@ import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcSubscriptionRequest implements InternalPlcSubscriptionRequest, InternalPlcFieldRequest {
+public class DefaultPlcSubscriptionRequest implements PlcSubscriptionRequest, XmlSerializable {
 
     private final PlcSubscriber subscriber;
 
-    private LinkedHashMap<String, SubscriptionPlcField> fields;
+    private LinkedHashMap<String, PlcSubscriptionField> fields;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
     public DefaultPlcSubscriptionRequest(@JsonProperty("subscriber") PlcSubscriber subscriber,
-                                         @JsonProperty("fields") LinkedHashMap<String, SubscriptionPlcField> fields) {
+                                         @JsonProperty("fields") LinkedHashMap<String, PlcSubscriptionField> fields) {
         this.subscriber = subscriber;
         this.fields = fields;
     }
@@ -70,43 +73,18 @@ public class DefaultPlcSubscriptionRequest implements InternalPlcSubscriptionReq
 
     @Override
     @JsonIgnore
-    public PlcField getField(String name) {
-        SubscriptionPlcField subscriptionPlcField = fields.get(name);
-        if (subscriptionPlcField == null) {
-            return null;
-        }
-        return subscriptionPlcField.getPlcField();
-    }
-
-    @Override
-    @JsonIgnore
-    public List<PlcField> getFields() {
-        return fields.values().stream().map(SubscriptionPlcField::getPlcField).collect(Collectors.toCollection(LinkedList::new));
+    public PlcSubscriptionField getField(String name) {
+        return fields.get(name);
     }
 
     @Override
     @JsonIgnore
-    public List<SubscriptionPlcField> getSubscriptionFields() {
-        return new LinkedList<>(fields.values());
+    public List<PlcSubscriptionField> getFields() {
+        return new ArrayList<>(fields.values());
     }
 
-    @Override
-    public Map<String, SubscriptionPlcField> getSubscriptionPlcFieldMap() {
-        return fields;
-    }
-
-    @Override
     @JsonIgnore
-    public List<Pair<String, PlcField>> getNamedFields() {
-        return fields.entrySet()
-            .stream()
-            .map(stringPlcFieldEntry -> Pair.of(stringPlcFieldEntry.getKey(), stringPlcFieldEntry.getValue().getPlcField()))
-            .collect(Collectors.toCollection(LinkedList::new));
-    }
-
-    @Override
-    @JsonIgnore
-    public List<Pair<String, SubscriptionPlcField>> getNamedSubscriptionFields() {
+    public List<Pair<String, PlcSubscriptionField>> getNamedFields() {
         return fields.entrySet()
             .stream()
             .map(stringPlcFieldEntry -> Pair.of(stringPlcFieldEntry.getKey(), stringPlcFieldEntry.getValue()))
@@ -117,6 +95,11 @@ public class DefaultPlcSubscriptionRequest implements InternalPlcSubscriptionReq
         return subscriber;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
     public static class Builder implements PlcSubscriptionRequest.Builder {
 
         private final PlcSubscriber subscriber;
@@ -152,11 +135,11 @@ public class DefaultPlcSubscriptionRequest implements InternalPlcSubscriptionReq
 
         @Override
         public PlcSubscriptionRequest build() {
-            LinkedHashMap<String, SubscriptionPlcField> parsedFields = new LinkedHashMap<>();
+            LinkedHashMap<String, PlcSubscriptionField> parsedFields = new LinkedHashMap<>();
 
             fields.forEach((name, builderItem) -> {
                 PlcField parsedField = fieldHandler.createField(builderItem.fieldQuery);
-                parsedFields.put(name, new SubscriptionPlcField(builderItem.plcSubscriptionType, parsedField, builderItem.duration));
+                parsedFields.put(name, new DefaultPlcSubscriptionField(builderItem.plcSubscriptionType, parsedField, builderItem.duration));
             });
             return new DefaultPlcSubscriptionRequest(subscriber, parsedFields);
         }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionResponse.java
index 7856ad1..afd6313 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionResponse.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcSubscriptionResponse.java
@@ -24,25 +24,30 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcResponse;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
+import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
 import java.util.Collection;
 import java.util.Map;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcSubscriptionResponse implements InternalPlcSubscriptionResponse {
+public class DefaultPlcSubscriptionResponse implements PlcSubscriptionResponse, PlcResponse, XmlSerializable {
 
-    private final InternalPlcSubscriptionRequest request;
+    private final PlcSubscriptionRequest request;
 
     private final Map<String, ResponseItem<PlcSubscriptionHandle>> values;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcSubscriptionResponse(@JsonProperty("request") InternalPlcSubscriptionRequest request,
+    public DefaultPlcSubscriptionResponse(@JsonProperty("request") PlcSubscriptionRequest request,
                                           @JsonProperty("values") Map<String, ResponseItem<PlcSubscriptionHandle>> values) {
         this.request = request;
         this.values = values;
@@ -69,7 +74,7 @@ public class DefaultPlcSubscriptionResponse implements InternalPlcSubscriptionRe
 
     @Override
     @JsonIgnore
-    public PlcField getField(String name) {
+    public PlcSubscriptionField getField(String name) {
         throw new PlcNotImplementedException("field access not possible as these come async");
     }
 
@@ -94,9 +99,13 @@ public class DefaultPlcSubscriptionResponse implements InternalPlcSubscriptionRe
         return values.values().stream().map(ResponseItem<PlcSubscriptionHandle>::getValue).collect(Collectors.toList());
     }
 
-    @Override
     public Map<String, ResponseItem<PlcSubscriptionHandle>> getValues() {
         return values;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionRequest.java
index 96c99db..c05d8d5 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionRequest.java
@@ -22,10 +22,12 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.messages.PlcRequest;
 import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
 import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -35,17 +37,17 @@ import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcUnsubscriptionRequest implements InternalPlcUnsubscriptionRequest, InternalPlcRequest {
+public class DefaultPlcUnsubscriptionRequest implements PlcUnsubscriptionRequest, PlcRequest, XmlSerializable {
 
     private final PlcSubscriber subscriber;
 
-    private final Collection<? extends InternalPlcSubscriptionHandle> internalPlcSubscriptionHandles;
+    private final List<PlcSubscriptionHandle> plcSubscriptionHandles;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
     public DefaultPlcUnsubscriptionRequest(@JsonProperty("subscriber") PlcSubscriber subscriber,
-                                           @JsonProperty("internalPlcSubscriptionHandles") Collection<? extends InternalPlcSubscriptionHandle> internalPlcSubscriptionHandles) {
+                                           @JsonProperty("internalPlcSubscriptionHandles") List<PlcSubscriptionHandle> plcSubscriptionHandles) {
         this.subscriber = subscriber;
-        this.internalPlcSubscriptionHandles = internalPlcSubscriptionHandles;
+        this.plcSubscriptionHandles = plcSubscriptionHandles;
     }
 
     @Override
@@ -54,19 +56,28 @@ public class DefaultPlcUnsubscriptionRequest implements InternalPlcUnsubscriptio
         return subscriber.unsubscribe(this);
     }
 
+    @Override
+    public List<PlcSubscriptionHandle> getSubscriptionHandles() {
+        return plcSubscriptionHandles;
+    }
+
     public PlcSubscriber getSubscriber() {
         return subscriber;
     }
 
+    public Collection<PlcSubscriptionHandle> getPlcSubscriptionHandles() {
+        return plcSubscriptionHandles;
+    }
+
     @Override
-    public Collection<? extends InternalPlcSubscriptionHandle> getInternalPlcSubscriptionHandles() {
-        return internalPlcSubscriptionHandles;
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
     }
 
     public static class Builder implements PlcUnsubscriptionRequest.Builder {
 
         private final PlcSubscriber subscriber;
-        private List<InternalPlcSubscriptionHandle> plcSubscriptionHandles;
+        private List<PlcSubscriptionHandle> plcSubscriptionHandles;
 
         public Builder(PlcSubscriber subscriber) {
             this.subscriber = subscriber;
@@ -74,20 +85,20 @@ public class DefaultPlcUnsubscriptionRequest implements InternalPlcUnsubscriptio
         }
 
         public PlcUnsubscriptionRequest.Builder addHandles(PlcSubscriptionHandle plcSubscriptionHandle) {
-            plcSubscriptionHandles.add((InternalPlcSubscriptionHandle) plcSubscriptionHandle);
+            plcSubscriptionHandles.add(plcSubscriptionHandle);
             return this;
         }
 
         @Override
         public PlcUnsubscriptionRequest.Builder addHandles(PlcSubscriptionHandle plcSubscriptionHandle1, PlcSubscriptionHandle... plcSubscriptionHandles) {
-            this.plcSubscriptionHandles.add((InternalPlcSubscriptionHandle) plcSubscriptionHandle1);
-            this.plcSubscriptionHandles.addAll(Arrays.stream(plcSubscriptionHandles).map(InternalPlcSubscriptionHandle.class::cast).collect(Collectors.toList()));
+            this.plcSubscriptionHandles.add(plcSubscriptionHandle1);
+            this.plcSubscriptionHandles.addAll(Arrays.stream(plcSubscriptionHandles).map(PlcSubscriptionHandle.class::cast).collect(Collectors.toList()));
             return this;
         }
 
         @Override
         public PlcUnsubscriptionRequest.Builder addHandles(Collection<PlcSubscriptionHandle> plcSubscriptionHandles) {
-            this.plcSubscriptionHandles.addAll(plcSubscriptionHandles.stream().map(InternalPlcSubscriptionHandle.class::cast).collect(Collectors.toList()));
+            this.plcSubscriptionHandles.addAll(plcSubscriptionHandles.stream().map(PlcSubscriptionHandle.class::cast).collect(Collectors.toList()));
             return this;
         }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionResponse.java
index 76b2e77..5887e2d 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionResponse.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcUnsubscriptionResponse.java
@@ -21,15 +21,19 @@ package org.apache.plc4x.java.spi.messages;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.messages.PlcResponse;
 import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
+import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcUnsubscriptionResponse implements InternalPlcUnsubscriptionResponse {
+public class DefaultPlcUnsubscriptionResponse implements PlcUnsubscriptionResponse, PlcResponse, XmlSerializable {
 
-    private final InternalPlcUnsubscriptionRequest request;
+    private final PlcUnsubscriptionRequest request;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcUnsubscriptionResponse(@JsonProperty("request") InternalPlcUnsubscriptionRequest request) {
+    public DefaultPlcUnsubscriptionResponse(@JsonProperty("request") PlcUnsubscriptionRequest request) {
         this.request = request;
     }
 
@@ -38,4 +42,9 @@ public class DefaultPlcUnsubscriptionResponse implements InternalPlcUnsubscripti
         return request;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
index 211fdaa..cbe4bf2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
@@ -24,36 +24,29 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Triple;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcFieldRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcList;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.apache.plc4x.java.spi.values.PlcList;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
 import org.apache.plc4x.java.spi.messages.utils.FieldValueItem;
+import org.w3c.dom.Element;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.TreeMap;
 import java.util.concurrent.CompletableFuture;
-import java.util.function.BiFunction;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, InternalPlcFieldRequest {
+public class DefaultPlcWriteRequest implements PlcWriteRequest, XmlSerializable {
 
     private final PlcWriter writer;
     private final LinkedHashMap<String, FieldValueItem> fields;
@@ -101,13 +94,11 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal
         return fields.get(name).getValue();
     }
 
-    @Override
     @JsonIgnore
     public List<PlcValue> getPlcValues() {
         return fields.values().stream().map(FieldValueItem::getValue).collect(Collectors.toCollection(LinkedList::new));
     }
 
-    @Override
     @JsonIgnore
     public List<Pair<String, PlcField>> getNamedFields() {
         return fields.entrySet()
@@ -125,7 +116,6 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal
         return writer;
     }
 
-    @Override
     @JsonIgnore
     public List<Triple<String, PlcField, PlcValue>> getNamedFieldTriples() {
         return fields.entrySet()
@@ -150,12 +140,17 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal
         return 1;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
     public static class Builder implements PlcWriteRequest.Builder {
 
         private final PlcWriter writer;
         private final PlcFieldHandler fieldHandler;
         private final PlcValueHandler valueHandler;
-        private final Map<String, BuilderItem<Object>> fields;
+        private final Map<String, Pair<String, Object[]>> fields;
 
         public Builder(PlcWriter writer, PlcFieldHandler fieldHandler, PlcValueHandler valueHandler) {
             this.writer = writer;
@@ -165,57 +160,24 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal
         }
 
         @Override
-        public <T> Builder addItem(String name, String fieldQuery, Object... values) {
-            return addItem(name, fieldQuery, values, valueHandler.of(values));
-        }
-
-        @Override
-        public <T> Builder addItem(String name, PlcField fieldQuery, Object... values) {
-            return addItem(name, fieldQuery, values, valueHandler.of(values));
+        public Builder addItem(String name, String fieldQuery, Object... values) {
+            fields.put(name, Pair.of(fieldQuery, values));
+            return this;
         }
 
         @Override
         public PlcWriteRequest build() {
             LinkedHashMap<String, FieldValueItem> parsedFields = new LinkedHashMap<>();
-            fields.forEach((name, builderItem) -> {
+            fields.forEach((name, fieldValues) -> {
                 // Compile the query string.
-                PlcField parsedField = builderItem.fieldQuery.get();
-                // Encode the payload.
-                // TODO: Depending on the field type, handle the PlcValue creation differently.
-                PlcValue value = builderItem.encoder.apply(parsedField, builderItem.values);
-                parsedFields.put(name, new FieldValueItem(parsedField, value));
+                String fieldQuery = fieldValues.getLeft();
+                PlcField field = fieldHandler.createField(fieldQuery);
+                Object[] value = fieldValues.getRight();
+                PlcValue plcValue = valueHandler.of(value);
+                parsedFields.put(name, new FieldValueItem(field, plcValue));
             });
             return new DefaultPlcWriteRequest(writer, parsedFields);
         }
-
-        private Builder addItem(String name, String fieldQuery, Object[] values, BiFunction<PlcField, Object[], PlcValue> encoder) {
-            if (fields.containsKey(name)) {
-                throw new PlcRuntimeException("Duplicate field definition '" + name + "'");
-            }
-            fields.put(name, new BuilderItem<>(() -> fieldHandler.createField(fieldQuery), values, encoder));
-            return this;
-        }
-
-        private Builder addItem(String name, PlcField field, Object[] values, BiFunction<PlcField, Object[], PlcValue> encoder) {
-            if (fields.containsKey(name)) {
-                throw new PlcRuntimeException("Duplicate field definition '" + name + "'");
-            }
-            fields.put(name, new BuilderItem<>(() -> field, values, encoder));
-            return this;
-        }
-
-        private static class BuilderItem<T> {
-            private final Supplier<PlcField> fieldQuery;
-            private final T[] values;
-            private final BiFunction<PlcField, T[], PlcValue> encoder;
-
-            private BuilderItem(Supplier<PlcField> fieldQuery, T[] values, BiFunction<PlcField, T[], PlcValue> encoder) {
-                this.fieldQuery = fieldQuery;
-                this.values = values;
-                this.encoder = encoder;
-            }
-        }
-
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteResponse.java
index f552de2..9ea0807 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteResponse.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteResponse.java
@@ -22,32 +22,31 @@ import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
 import java.util.Collection;
 import java.util.Map;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class DefaultPlcWriteResponse implements InternalPlcWriteResponse {
+public class DefaultPlcWriteResponse implements PlcWriteResponse, XmlSerializable {
 
-    private final InternalPlcWriteRequest request;
+    private final PlcWriteRequest request;
     private final Map<String, PlcResponseCode> values;
 
     @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
-    public DefaultPlcWriteResponse(@JsonProperty("request") InternalPlcWriteRequest request,
+    public DefaultPlcWriteResponse(@JsonProperty("request") PlcWriteRequest request,
                                    @JsonProperty("values") Map<String, PlcResponseCode> values) {
         this.request = request;
         this.values = values;
     }
 
     @Override
-    public Map<String, PlcResponseCode> getValues() {
-        return values;
-    }
-
-    @Override
-    public InternalPlcWriteRequest getRequest() {
+    public PlcWriteRequest getRequest() {
         return request;
     }
 
@@ -69,4 +68,9 @@ public class DefaultPlcWriteResponse implements InternalPlcWriteResponse {
         return values.get(name);
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldRequest.java
deleted file mode 100644
index 0d54c9d..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldRequest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.plc4x.java.api.messages.PlcFieldRequest;
-import org.apache.plc4x.java.api.model.PlcField;
-
-import java.util.List;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcFieldRequest extends PlcFieldRequest, InternalPlcRequest {
-
-    List<Pair<String, PlcField>> getNamedFields();
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldResponse.java
deleted file mode 100644
index 04d3c42..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcFieldResponse.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcFieldResponse;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcFieldResponse extends PlcFieldResponse {
-
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcMessage.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcMessage.java
deleted file mode 100644
index 14d6a67..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcMessage.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcMessage {
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryRequest.java
deleted file mode 100644
index b0965e2..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryRequest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcProprietaryRequest<REQUEST> extends PlcProprietaryRequest<REQUEST>, InternalPlcRequest {
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryResponse.java
deleted file mode 100644
index bf2f81b..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcProprietaryResponse.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcProprietaryResponse<RESPONSE> extends PlcProprietaryResponse<RESPONSE>, InternalPlcResponse {
-}
\ No newline at end of file
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadRequest.java
deleted file mode 100644
index d631b5d..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadRequest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcReadRequest;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcReadRequest extends PlcReadRequest, InternalPlcFieldRequest, InternalPlcRequest {
-
-}
-
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadResponse.java
deleted file mode 100644
index b0b2e89..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcReadResponse.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcReadResponse;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-
-import java.util.Map;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcReadResponse extends PlcReadResponse, InternalPlcResponse {
-
-    Map<String, ResponseItem<PlcValue>> getValues();
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcRequest.java
deleted file mode 100644
index 1b1a988..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcRequest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcRequest;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcRequest extends PlcRequest, InternalPlcMessage {
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcResponse.java
deleted file mode 100644
index 28062c9..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcResponse.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcResponse;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcResponse extends PlcResponse {
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionEvent.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionEvent.java
deleted file mode 100644
index 96e0b81..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionEvent.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcSubscriptionEvent extends PlcSubscriptionEvent {
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionRequest.java
deleted file mode 100644
index 1fbe4d4..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionRequest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
-
-import java.util.List;
-import java.util.Map;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcSubscriptionRequest extends PlcSubscriptionRequest, InternalPlcFieldRequest {
-
-    List<SubscriptionPlcField> getSubscriptionFields();
-
-    Map<String, SubscriptionPlcField> getSubscriptionPlcFieldMap();
-
-    List<Pair<String, SubscriptionPlcField>> getNamedSubscriptionFields();
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionResponse.java
deleted file mode 100644
index f7304e0..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcSubscriptionResponse.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
-import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-
-import java.util.Map;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcSubscriptionResponse extends PlcSubscriptionResponse, InternalPlcResponse {
-    Map<String, ResponseItem<PlcSubscriptionHandle>> getValues();
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionRequest.java
deleted file mode 100644
index 24fdf25..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcUnsubscriptionRequest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
-
-import java.util.Collection;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcUnsubscriptionRequest extends PlcUnsubscriptionRequest, InternalPlcRequest {
-
-    Collection<? extends InternalPlcSubscriptionHandle> getInternalPlcSubscriptionHandles();
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteRequest.java
deleted file mode 100644
index ccb1568..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/InternalPlcWriteRequest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import org.apache.commons.lang3.tuple.Triple;
-import org.apache.plc4x.java.api.messages.PlcWriteRequest;
-import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.value.PlcValue;
-
-import java.util.List;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public interface InternalPlcWriteRequest extends PlcWriteRequest, InternalPlcRequest {
-
-    PlcValue getPlcValue(String name);
-
-    List<PlcValue> getPlcValues();
-
-    List<Triple<String, PlcField, PlcValue>> getNamedFieldTriples();
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRawMessage.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRawMessage.java
deleted file mode 100644
index d083277..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRawMessage.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.messages;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import io.netty.buffer.ByteBuf;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
-public class PlcRawMessage implements PlcProtocolMessage {
-
-    private final ByteBuf userData;
-    private final PlcProtocolMessage parent;
-
-    public PlcRawMessage(ByteBuf userData) {
-        this(userData, null);
-    }
-
-    public PlcRawMessage(ByteBuf userData, PlcProtocolMessage parent) {
-        this.userData = userData;
-        this.parent = parent;
-    }
-
-    public ByteBuf getUserData() {
-        return userData;
-    }
-
-    @Override
-    public PlcProtocolMessage getParent() {
-        return parent;
-    }
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRequestContainer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRequestContainer.java
index 481ca1c..4779a36 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRequestContainer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcRequestContainer.java
@@ -18,6 +18,9 @@
  */
 package org.apache.plc4x.java.spi.messages;
 
+import org.apache.plc4x.java.api.messages.PlcRequest;
+import org.apache.plc4x.java.api.messages.PlcResponse;
+
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 
@@ -27,7 +30,7 @@ import java.util.concurrent.CompletableFuture;
  * @param <T> type of request.
  * @param <R> type of response.
  */
-public class PlcRequestContainer<T extends InternalPlcRequest, R extends InternalPlcResponse> implements PlcProtocolMessage {
+public class PlcRequestContainer<T extends PlcRequest, R extends PlcResponse> implements PlcProtocolMessage {
 
     private final T request;
     private final CompletableFuture<R> responseFuture;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/utils/ResponseItem.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/utils/ResponseItem.java
index 1435f7c..f1c10df 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/utils/ResponseItem.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/utils/ResponseItem.java
@@ -19,8 +19,10 @@ under the License.
 package org.apache.plc4x.java.spi.messages.utils;
 
 import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Element;
 
-public class ResponseItem<T> {
+public class ResponseItem<T> implements XmlSerializable {
 
     private final PlcResponseCode code;
     private final T value;
@@ -38,4 +40,15 @@ public class ResponseItem<T> {
         return value;
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        parent.setAttribute("result", code.name());
+        if(value != null) {
+            if (!(value instanceof XmlSerializable)) {
+                throw new RuntimeException("Error serializing. Field value doesn't implement XmlSerializable");
+            }
+            ((XmlSerializable) value).xmlSerialize(parent);
+        }
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcConsumerRegistration.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcConsumerRegistration.java
index bcf7830..d4f5321 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcConsumerRegistration.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcConsumerRegistration.java
@@ -19,34 +19,36 @@
 package org.apache.plc4x.java.spi.model;
 
 import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
+import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
+import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.spi.messages.PlcSubscriber;
 
 import java.util.Arrays;
-import java.util.Collection;
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Consumer;
 
-public class DefaultPlcConsumerRegistration implements InternalPlcConsumerRegistration {
+public class DefaultPlcConsumerRegistration implements PlcConsumerRegistration {
 
     private final PlcSubscriber plcSubscriber;
 
-    private final Collection<InternalPlcSubscriptionHandle> handles;
+    private final List<PlcSubscriptionHandle> handles;
 
     private final int consumerHash;
 
-    public DefaultPlcConsumerRegistration(PlcSubscriber plcSubscriber, Consumer<PlcSubscriptionEvent> consumer, InternalPlcSubscriptionHandle... handles) {
+    public DefaultPlcConsumerRegistration(PlcSubscriber plcSubscriber, Consumer<PlcSubscriptionEvent> consumer, PlcSubscriptionHandle... handles) {
         this.plcSubscriber = plcSubscriber;
         this.handles = Arrays.asList(Objects.requireNonNull(handles));
         this.consumerHash = Objects.requireNonNull(consumer).hashCode();
     }
 
     @Override
-    public int getConsumerHash() {
+    public Integer getConsumerId() {
         return consumerHash;
     }
 
     @Override
-    public Collection<InternalPlcSubscriptionHandle> getAssociatedHandles() {
+    public List<PlcSubscriptionHandle> getSubscriptionHandles() {
         return handles;
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/SubscriptionPlcField.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionField.java
similarity index 86%
rename from plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/SubscriptionPlcField.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionField.java
index 2116064..ce22970 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/SubscriptionPlcField.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionField.java
@@ -19,6 +19,7 @@
 package org.apache.plc4x.java.spi.model;
 
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.types.PlcSubscriptionType;
 
 import java.time.Duration;
@@ -27,7 +28,7 @@ import java.util.Optional;
 /**
  * special {@link PlcField} which adds a {@link PlcSubscriptionType}.
  */
-public class SubscriptionPlcField {
+public class DefaultPlcSubscriptionField implements PlcSubscriptionField {
 
     private final PlcSubscriptionType plcSubscriptionType;
 
@@ -35,7 +36,7 @@ public class SubscriptionPlcField {
 
     private final Duration duration;
 
-    public SubscriptionPlcField(PlcSubscriptionType plcSubscriptionType, PlcField plcField, Duration duration) {
+    public DefaultPlcSubscriptionField(PlcSubscriptionType plcSubscriptionType, PlcField plcField, Duration duration) {
         this.plcSubscriptionType = plcSubscriptionType;
         this.plcField = plcField;
         this.duration = duration;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionHandle.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionHandle.java
index 9d4a01b..c9d687b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionHandle.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/DefaultPlcSubscriptionHandle.java
@@ -21,13 +21,14 @@ package org.apache.plc4x.java.spi.model;
 
 import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
+import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.spi.messages.PlcSubscriber;
 
 import java.util.Collections;
 import java.util.function.Consumer;
 
 // Warning: do not override equals and hashCode as these should not include the plcSubscriber.
-public class DefaultPlcSubscriptionHandle implements InternalPlcSubscriptionHandle {
+public class DefaultPlcSubscriptionHandle implements PlcSubscriptionHandle {
 
     private final PlcSubscriber plcSubscriber;
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcConsumerRegistration.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcConsumerRegistration.java
deleted file mode 100644
index 34cb0ef..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcConsumerRegistration.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.model;
-
-import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
-import org.apache.plc4x.java.spi.messages.InternalPlcMessage;
-
-import java.util.Collection;
-
-public interface InternalPlcConsumerRegistration extends PlcConsumerRegistration, InternalPlcMessage {
-
-    int getConsumerHash();
-
-    Collection<? extends InternalPlcSubscriptionHandle> getAssociatedHandles();
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcSubscriptionHandle.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcSubscriptionHandle.java
deleted file mode 100644
index 33d4dd0..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/model/InternalPlcSubscriptionHandle.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.model;
-
-import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.messages.InternalPlcMessage;
-
-public interface InternalPlcSubscriptionHandle extends PlcSubscriptionHandle, InternalPlcMessage {
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/BaseOptimizer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/BaseOptimizer.java
index 0933ec5..2e48fd2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/BaseOptimizer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/optimizer/BaseOptimizer.java
@@ -26,8 +26,6 @@ import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.context.DriverContext;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 
 import java.util.*;
@@ -58,7 +56,7 @@ public abstract class BaseOptimizer {
                 }
             }
         }
-        return new DefaultPlcReadResponse((InternalPlcReadRequest) readRequest, fields);
+        return new DefaultPlcReadResponse(readRequest, fields);
     }
 
     protected List<PlcRequest> processWriteRequest(PlcWriteRequest writeRequest, DriverContext driverContext) {
@@ -80,7 +78,7 @@ public abstract class BaseOptimizer {
                 }
             }
         }
-        return new DefaultPlcWriteResponse((InternalPlcWriteRequest) writeRequest, fields);
+        return new DefaultPlcWriteResponse(writeRequest, fields);
     }
 
     protected List<PlcRequest> processSubscriptionRequest(PlcSubscriptionRequest subscriptionRequest,
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/protocol/SingleItemToSingleRequestProtocol.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/protocol/SingleItemToSingleRequestProtocol.java
deleted file mode 100644
index fcbc2ac..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/protocol/SingleItemToSingleRequestProtocol.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.spi.protocol;
-
-import io.netty.channel.*;
-import io.netty.util.Timeout;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.PromiseCombiner;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.commons.lang3.tuple.Triple;
-import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-import org.apache.plc4x.java.api.exceptions.PlcTimeoutException;
-import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
-import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
-import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse;
-import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionResponse;
-import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcFieldRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcSubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcSubscriptionResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcUnsubscriptionRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.PlcReader;
-import org.apache.plc4x.java.spi.messages.PlcRequestContainer;
-import org.apache.plc4x.java.spi.messages.PlcSubscriber;
-import org.apache.plc4x.java.spi.messages.PlcWriter;
-import org.apache.plc4x.java.spi.messages.utils.FieldValueItem;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
-import org.apache.plc4x.java.spi.model.InternalPlcSubscriptionHandle;
-import org.apache.plc4x.java.spi.model.SubscriptionPlcField;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-
-/**
- * This layer can be used to split a {@link org.apache.plc4x.java.api.messages.PlcRequest} which addresses multiple {@link PlcField}s into multiple subsequent {@link org.apache.plc4x.java.api.messages.PlcRequest}s.
- */
-// TODO: add split config so we can override special requests that are allready splitted downstream
-public class SingleItemToSingleRequestProtocol extends ChannelDuplexHandler {
-
-    public static final Logger LOGGER = LoggerFactory.getLogger(SingleItemToSingleRequestProtocol.class);
-
-    private final Timer timer;
-
-    private final PlcReader reader;
-
-    private final PlcWriter writer;
-
-    private final PlcSubscriber subscriber;
-
-    // TODO: maybe better get from map
-    private long defaultReceiveTimeout;
-
-    private PendingWriteQueue queue;
-
-    private ConcurrentMap<PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>, Timeout> scheduledTimeouts;
-
-    // Map to track send subcontainers
-    private ConcurrentMap<Integer, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> sentButUnacknowledgedSubContainer;
-
-    // Map to map tdpu to original parent container
-    // TODO: currently this could be supplied via param, only reason to keep would be for statistics.
-    private ConcurrentMap<Integer, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> correlationToParentContainer;
-
-    // Map to track tdpus per container
-    // TODO: currently this could be supplied via param, only reason to keep would be for statistics.
-    private ConcurrentMap<PlcRequestContainer<?, ?>, Set<Integer>> containerCorrelationIdMap;
-
-    // Map to track a list of responses per parent container
-    private ConcurrentMap<PlcRequestContainer<?, ?>, Queue<InternalPlcResponse>> responsesToBeDelivered;
-
-    private AtomicInteger correlationIdGenerator;
-
-    // TODO: maybe put in map per day or per hour
-    private AtomicLong deliveredContainers;
-
-    private AtomicLong erroredContainers;
-
-    private AtomicLong deliveredItems;
-
-    private AtomicLong erroredItems;
-
-    private SplitConfig splitConfig;
-
-    public SingleItemToSingleRequestProtocol(PlcReader reader, PlcWriter writer, PlcSubscriber subscriber, Timer timer) {
-        this(reader, writer, subscriber, timer, new SplitConfig());
-    }
-
-    public SingleItemToSingleRequestProtocol(PlcReader reader, PlcWriter writer, PlcSubscriber subscriber, Timer timer, SplitConfig splitConfig) {
-        this(reader, writer, subscriber, timer, splitConfig, true);
-    }
-
-    public SingleItemToSingleRequestProtocol(PlcReader reader, PlcWriter writer, PlcSubscriber subscriber, Timer timer, SplitConfig splitConfig, boolean betterImplementationPossible) {
-        this(reader, writer, subscriber, timer, TimeUnit.SECONDS.toMillis(30), splitConfig, betterImplementationPossible);
-    }
-
-    public SingleItemToSingleRequestProtocol(PlcReader reader, PlcWriter writer, PlcSubscriber subscriber, Timer timer, long defaultReceiveTimeout, SplitConfig splitConfig, boolean betterImplementationPossible) {
-        this.reader = reader;
-        this.writer = writer;
-        this.subscriber = subscriber;
-        this.timer = timer;
-        this.defaultReceiveTimeout = defaultReceiveTimeout;
-        this.splitConfig = splitConfig;
-        if (this.splitConfig == null) {
-            this.splitConfig = new SplitConfig();
-        }
-        if (betterImplementationPossible) {
-            String callStack = Arrays.stream(Thread.currentThread().getStackTrace())
-                .map(StackTraceElement::toString)
-                .collect(Collectors.joining("\n"));
-            LOGGER.warn("Unoptimized Usage of {} detected at:\n{}", this.getClass(), callStack);
-            LOGGER.info("Consider implementing item splitting native to the protocol.");
-        }
-    }
-
-    @Override
-    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
-        this.queue = new PendingWriteQueue(ctx);
-        this.scheduledTimeouts = new ConcurrentHashMap<>();
-        this.sentButUnacknowledgedSubContainer = new ConcurrentHashMap<>();
-        this.correlationToParentContainer = new ConcurrentHashMap<>();
-        this.containerCorrelationIdMap = new ConcurrentHashMap<>();
-        this.responsesToBeDelivered = new ConcurrentHashMap<>();
-        this.correlationIdGenerator = new AtomicInteger();
-        this.deliveredItems = new AtomicLong();
-        this.erroredItems = new AtomicLong();
-        this.deliveredContainers = new AtomicLong();
-        this.erroredContainers = new AtomicLong();
-        super.channelRegistered(ctx);
-    }
-
-    @Override
-    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
-        this.queue.removeAndWriteAll();
-        this.scheduledTimeouts.clear();
-        this.sentButUnacknowledgedSubContainer.clear();
-        this.correlationToParentContainer.clear();
-        this.containerCorrelationIdMap.clear();
-        this.responsesToBeDelivered.clear();
-        this.correlationIdGenerator.set(0);
-        this.deliveredItems.set(0);
-        this.erroredItems.set(0);
-        this.deliveredContainers.set(0);
-        this.erroredContainers.set(0);
-        super.channelUnregistered(ctx);
-    }
-
-    @Override
-    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        // Send everything so we get a proper failure for those pending writes
-        this.queue.removeAndWriteAll();
-        for (Timeout timeout : this.scheduledTimeouts.values()) {
-            timeout.cancel();
-        }
-        this.scheduledTimeouts.clear();
-        this.sentButUnacknowledgedSubContainer.clear();
-        this.correlationToParentContainer.clear();
-        this.containerCorrelationIdMap.clear();
-        this.responsesToBeDelivered.clear();
-        this.correlationIdGenerator.set(0);
-        this.deliveredItems.set(0);
-        this.erroredItems.set(0);
-        this.deliveredContainers.set(0);
-        this.erroredContainers.set(0);
-        super.channelInactive(ctx);
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Decoding
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-    protected void tryFinish(Integer currentTdpu, InternalPlcResponse msg, CompletableFuture<InternalPlcResponse> originalResponseFuture) {
-        deliveredItems.incrementAndGet();
-        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> subPlcRequestContainer = sentButUnacknowledgedSubContainer.remove(currentTdpu);
-        LOGGER.info("{} got acknowledged", subPlcRequestContainer);
-        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> originalPlcRequestContainer = correlationToParentContainer.remove(currentTdpu);
-        if (originalPlcRequestContainer == null) {
-            LOGGER.warn("Unrelated package received {}", msg);
-            return;
-        }
-        Queue<InternalPlcResponse> correlatedResponseItems = responsesToBeDelivered.computeIfAbsent(originalPlcRequestContainer, ignore -> new ConcurrentLinkedQueue<>());
-        correlatedResponseItems.add(msg);
-        Set<Integer> integers = containerCorrelationIdMap.get(originalPlcRequestContainer);
-        integers.remove(currentTdpu);
-        if (integers.isEmpty()) {
-            deliveredContainers.incrementAndGet();
-            Timeout timeout = scheduledTimeouts.remove(originalPlcRequestContainer);
-            if (timeout != null) {
-                timeout.cancel();
-            }
-
-            InternalPlcResponse plcResponse;
-            if (originalPlcRequestContainer.getRequest() instanceof InternalPlcReadRequest) {
-                InternalPlcReadRequest internalPlcReadRequest = (InternalPlcReadRequest) originalPlcRequestContainer.getRequest();
-                HashMap<String, ResponseItem<PlcValue>> fields = new HashMap<>();
-
-                correlatedResponseItems.stream()
-                    .map(InternalPlcReadResponse.class::cast)
-                    .map(InternalPlcReadResponse::getValues)
-                    .forEach(stringPairMap -> stringPairMap.forEach(fields::put));
-
-                plcResponse = new DefaultPlcReadResponse(internalPlcReadRequest, fields);
-            } else if (originalPlcRequestContainer.getRequest() instanceof InternalPlcWriteRequest) {
-                InternalPlcWriteRequest internalPlcWriteRequest = (InternalPlcWriteRequest) originalPlcRequestContainer.getRequest();
-                HashMap<String, PlcResponseCode> values = new HashMap<>();
-
-                correlatedResponseItems.stream()
-                    .map(InternalPlcWriteResponse.class::cast)
-                    .map(InternalPlcWriteResponse::getValues)
-                    .forEach(stringPairMap -> stringPairMap.forEach(values::put));
-
-                plcResponse = new DefaultPlcWriteResponse(internalPlcWriteRequest, values);
-            } else if (originalPlcRequestContainer.getRequest() instanceof InternalPlcSubscriptionRequest) {
-                InternalPlcSubscriptionRequest internalPlcSubscriptionRequest = (InternalPlcSubscriptionRequest) originalPlcRequestContainer.getRequest();
-                HashMap<String, ResponseItem<PlcSubscriptionHandle>> fields = new HashMap<>();
-
-                correlatedResponseItems.stream()
-                    .map(InternalPlcSubscriptionResponse.class::cast)
-                    .map(InternalPlcSubscriptionResponse::getValues)
-                    .forEach(stringPairMap -> stringPairMap.forEach(fields::put));
-
-                plcResponse = new DefaultPlcSubscriptionResponse(internalPlcSubscriptionRequest, fields);
-            } else if (originalPlcRequestContainer.getRequest() instanceof InternalPlcUnsubscriptionRequest) {
-                InternalPlcUnsubscriptionRequest internalPlcUnsubscriptionRequest = (InternalPlcUnsubscriptionRequest) originalPlcRequestContainer.getRequest();
-                plcResponse = new DefaultPlcUnsubscriptionResponse(internalPlcUnsubscriptionRequest);
-            } else {
-                errored(currentTdpu, new PlcProtocolException("Unknown type detected " + originalPlcRequestContainer.getRequest().getClass()), originalResponseFuture);
-                return;
-            }
-            responsesToBeDelivered.remove(originalPlcRequestContainer);
-            containerCorrelationIdMap.remove(originalPlcRequestContainer);
-            originalResponseFuture.complete(plcResponse);
-        }
-    }
-
-    protected void errored(Integer currentTdpu, Throwable throwable, CompletableFuture<InternalPlcResponse> originalResponseFuture) {
-        erroredItems.incrementAndGet();
-        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> subPlcRequestContainer = sentButUnacknowledgedSubContainer.remove(currentTdpu);
-        LOGGER.info("{} got errored", subPlcRequestContainer);
-
-
-        PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> originalPlcRequestContainer = correlationToParentContainer.remove(currentTdpu);
-        if (originalPlcRequestContainer == null) {
-            LOGGER.warn("Unrelated error received tdpu:{}", currentTdpu, throwable);
-        } else {
-            erroredContainers.incrementAndGet();
-            Timeout timeout = scheduledTimeouts.remove(originalPlcRequestContainer);
-            if (timeout != null) {
-                timeout.cancel();
-            }
-            responsesToBeDelivered.remove(originalPlcRequestContainer);
-
-            Set<Integer> tdpus = containerCorrelationIdMap.remove(originalPlcRequestContainer);
-            if (tdpus != null) {
-                tdpus.forEach(tdpu -> {
-                    // TODO: technically the other items didn't error so do we increment?
-                    //erroredItems.incrementAndGet();
-                    sentButUnacknowledgedSubContainer.remove(tdpu);
-                    correlationToParentContainer.remove(tdpu);
-                });
-            }
-
-            LOGGER.warn("PlcRequestContainer {} and correlationId {} failed ", correlationToParentContainer, currentTdpu, throwable);
-            originalResponseFuture.completeExceptionally(throwable);
-        }
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Encoding
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
-        if (msg instanceof PlcRequestContainer) {
-            @SuppressWarnings("unchecked")
-            PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> in = (PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>) msg;
-            Set<Integer> tdpus = containerCorrelationIdMap.computeIfAbsent(in, plcRequestContainer -> ConcurrentHashMap.newKeySet());
-
-            Timeout timeout = timer.newTimeout(timeout_ -> handleTimeout(timeout_, in, tdpus, System.nanoTime()), defaultReceiveTimeout, TimeUnit.MILLISECONDS);
-            scheduledTimeouts.put(in, timeout);
-
-            // Create a promise that has to be called multiple times.
-            PromiseCombiner promiseCombiner = new PromiseCombiner();
-            InternalPlcRequest request = in.getRequest();
-            if (request instanceof InternalPlcFieldRequest && (splitConfig.splitRead || splitConfig.splitWrite || splitConfig.splitSubscription)) {
-                InternalPlcFieldRequest internalPlcFieldRequest = (InternalPlcFieldRequest) request;
-
-                if (internalPlcFieldRequest instanceof InternalPlcReadRequest && splitConfig.splitRead) {
-                    InternalPlcReadRequest internalPlcReadRequest = (InternalPlcReadRequest) internalPlcFieldRequest;
-                    internalPlcReadRequest.getNamedFields().forEach(field -> {
-                        ChannelPromise subPromise = new DefaultChannelPromise(promise.channel());
-
-                        Integer tdpu = correlationIdGenerator.getAndIncrement();
-                        CompletableFuture<InternalPlcResponse> correlatedCompletableFuture = new CompletableFuture<>();
-                        // Important: don't chain to above as we want the above to be completed not the result of when complete
-                        correlatedCompletableFuture
-                            .thenApply(InternalPlcResponse.class::cast)
-                            .whenComplete((internalPlcResponse, throwable) -> {
-                                if (throwable != null) {
-                                    errored(tdpu, throwable, in.getResponseFuture());
-                                } else {
-                                    tryFinish(tdpu, internalPlcResponse, in.getResponseFuture());
-                                }
-                            });
-                        PlcRequestContainer<CorrelatedPlcReadRequest, InternalPlcResponse> correlatedPlcRequestContainer = new PlcRequestContainer<>(CorrelatedPlcReadRequest.of(reader, field, tdpu), correlatedCompletableFuture);
-                        correlationToParentContainer.put(tdpu, in);
-                        queue.add(correlatedPlcRequestContainer, subPromise);
-                        if (!tdpus.add(tdpu)) {
-                            throw new IllegalStateException("AtomicInteger should not create duplicated ids: " + tdpu);
-                        }
-                        promiseCombiner.add((Future) subPromise);
-                    });
-                } else if (internalPlcFieldRequest instanceof InternalPlcWriteRequest && splitConfig.splitWrite) {
-                    InternalPlcWriteRequest internalPlcWriteRequest = (InternalPlcWriteRequest) internalPlcFieldRequest;
-                    internalPlcWriteRequest.getNamedFieldTriples().forEach(valueTriple -> {
-                        ChannelPromise subPromise = new DefaultChannelPromise(promise.channel());
-
-                        Integer tdpu = correlationIdGenerator.getAndIncrement();
-                        CompletableFuture<InternalPlcResponse> correlatedCompletableFuture = new CompletableFuture<>();
-                        // Important: don't chain to above as we want the above to be completed not the result of when complete
-                        correlatedCompletableFuture
-                            .thenApply(InternalPlcResponse.class::cast)
-                            .whenComplete((internalPlcResponse, throwable) -> {
-                                if (throwable != null) {
-                                    errored(tdpu, throwable, in.getResponseFuture());
-                                } else {
-                                    tryFinish(tdpu, internalPlcResponse, in.getResponseFuture());
-                                }
-                            });
-                        PlcRequestContainer<CorrelatedPlcWriteRequest, InternalPlcResponse> correlatedPlcRequestContainer = new PlcRequestContainer<>(CorrelatedPlcWriteRequest.of(writer, valueTriple, tdpu), correlatedCompletableFuture);
-                        correlationToParentContainer.put(tdpu, in);
-                        queue.add(correlatedPlcRequestContainer, subPromise);
-                        if (!tdpus.add(tdpu)) {
-                            throw new IllegalStateException("AtomicInteger should not create duplicated ids: " + tdpu);
-                        }
-                        promiseCombiner.add((Future) subPromise);
-                    });
-                } else if (internalPlcFieldRequest instanceof InternalPlcSubscriptionRequest && splitConfig.splitSubscription) {
-                    InternalPlcSubscriptionRequest internalPlcSubscriptionRequest = (InternalPlcSubscriptionRequest) internalPlcFieldRequest;
-                    internalPlcSubscriptionRequest.getNamedSubscriptionFields().forEach(field -> {
-                        ChannelPromise subPromise = new DefaultChannelPromise(promise.channel());
-
-                        Integer tdpu = correlationIdGenerator.getAndIncrement();
-                        CompletableFuture<InternalPlcResponse> correlatedCompletableFuture = new CompletableFuture<>();
-                        // Important: don't chain to above as we want the above to be completed not the result of when complete
-                        correlatedCompletableFuture
-                            .thenApply(InternalPlcResponse.class::cast)
-                            .whenComplete((internalPlcResponse, throwable) -> {
-                                if (throwable != null) {
-                                    errored(tdpu, throwable, in.getResponseFuture());
-                                } else {
-                                    tryFinish(tdpu, internalPlcResponse, in.getResponseFuture());
-                                }
-                            });
-                        PlcRequestContainer<CorrelatedPlcSubscriptionRequest, InternalPlcResponse> correlatedPlcRequestContainer = new PlcRequestContainer<>(CorrelatedPlcSubscriptionRequest.of(subscriber, field, tdpu), correlatedCompletableFuture);
-                        correlationToParentContainer.put(tdpu, in);
-                        queue.add(correlatedPlcRequestContainer, subPromise);
-                        if (!tdpus.add(tdpu)) {
-                            throw new IllegalStateException("AtomicInteger should not create duplicated ids: " + tdpu);
-                        }
-                        promiseCombiner.add((Future) subPromise);
-                    });
-                } else {
-                    throw new PlcProtocolException("Unmapped request type " + request.getClass());
-                }
-            } else if (request instanceof InternalPlcUnsubscriptionRequest && splitConfig.splitUnsubscription) {
-                InternalPlcUnsubscriptionRequest internalPlcUnsubscriptionRequest = (InternalPlcUnsubscriptionRequest) request;
-                internalPlcUnsubscriptionRequest.getInternalPlcSubscriptionHandles().forEach(handle -> {
-                    ChannelPromise subPromise = new DefaultChannelPromise(promise.channel());
-
-                    Integer tdpu = correlationIdGenerator.getAndIncrement();
-                    CompletableFuture<InternalPlcResponse> correlatedCompletableFuture = new CompletableFuture<>();
-                    // Important: don't chain to above as we want the above to be completed not the result of when complete
-                    correlatedCompletableFuture
-                        .thenApply(InternalPlcResponse.class::cast)
-                        .whenComplete((internalPlcResponse, throwable) -> {
-                            if (throwable != null) {
-                                errored(tdpu, throwable, in.getResponseFuture());
-                            } else {
-                                tryFinish(tdpu, internalPlcResponse, in.getResponseFuture());
-                            }
-                        });
-                    PlcRequestContainer<CorrelatedPlcUnsubscriptionRequest, InternalPlcResponse> correlatedPlcRequestContainer = new PlcRequestContainer<>(CorrelatedPlcUnsubscriptionRequest.of(subscriber, handle, tdpu), correlatedCompletableFuture);
-                    correlationToParentContainer.put(tdpu, in);
-                    queue.add(correlatedPlcRequestContainer, subPromise);
-                    if (!tdpus.add(tdpu)) {
-                        throw new IllegalStateException("AtomicInteger should not create duplicated ids: " + tdpu);
-                    }
-                    promiseCombiner.add((Future) subPromise);
-                });
-            } else {
-                ChannelPromise subPromise = new DefaultChannelPromise(promise.channel());
-                queue.add(msg, subPromise);
-                promiseCombiner.add((Future) subPromise);
-            }
-
-            promiseCombiner.finish(promise);
-
-            // Start sending the queue content.
-            trySendingMessages(ctx);
-        } else {
-            super.write(ctx, msg, promise);
-        }
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    // Helpers
-    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @SuppressWarnings("unchecked")
-    protected synchronized void trySendingMessages(ChannelHandlerContext ctx) {
-        while (queue.size() > 0) {
-            // Get the RequestItem that is up next in the queue.
-            PlcRequestContainer currentItem = (PlcRequestContainer) queue.current();
-            InternalPlcRequest request = currentItem.getRequest();
-
-            // Send the TPDU.
-            try {
-                ChannelFuture channelFuture = queue.removeAndWrite();
-                ctx.flush();
-                if (channelFuture == null) {
-                    break;
-                }
-            } catch (Exception e) {
-                LOGGER.error("Error sending more queues messages", e);
-                ctx.fireExceptionCaught(e);
-            }
-
-            if (request instanceof CorrelatedPlcRequest) {
-                CorrelatedPlcRequest correlatedPlcRequest = (CorrelatedPlcRequest) request;
-
-                // Add it to the list of sentButUnacknowledgedSubContainer.
-                sentButUnacknowledgedSubContainer.put(correlatedPlcRequest.getTdpu(), currentItem);
-
-                LOGGER.debug("container with id {} sent: ", correlatedPlcRequest.getTdpu(), currentItem);
-            }
-        }
-        ctx.flush();
-    }
-
-    private void handleTimeout(Timeout timeout, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse> in, Set<Integer> tdpus, long scheduledAt) {
-        if (timeout.isCancelled()) {
-            LOGGER.debug("container {} with timeout {} got canceled", in, timeout);
-            return;
-        }
-        LOGGER.warn("container {} timed out:{}", in, timeout);
-        erroredContainers.incrementAndGet();
-        responsesToBeDelivered.remove(in);
-        containerCorrelationIdMap.remove(in);
-        tdpus.forEach(tdpu -> {
-            erroredItems.incrementAndGet();
-            sentButUnacknowledgedSubContainer.remove(tdpu);
-            correlationToParentContainer.remove(tdpu);
-        });
-        in.getResponseFuture().completeExceptionally(new PlcTimeoutException(System.nanoTime() - scheduledAt));
-    }
-
-    protected interface CorrelatedPlcRequest extends InternalPlcRequest {
-
-        int getTdpu();
-    }
-
-    protected static class CorrelatedPlcReadRequest extends DefaultPlcReadRequest implements CorrelatedPlcRequest {
-
-        protected final int tdpu;
-
-        protected CorrelatedPlcReadRequest(PlcReader reader, LinkedHashMap<String, PlcField> fields, int tdpu) {
-            super(reader, fields);
-            this.tdpu = tdpu;
-        }
-
-        protected static CorrelatedPlcReadRequest of(PlcReader reader, Pair<String, PlcField> stringPlcFieldPair, int tdpu) {
-            LinkedHashMap<String, PlcField> fields = new LinkedHashMap<>();
-            fields.put(stringPlcFieldPair.getKey(), stringPlcFieldPair.getValue());
-            return new CorrelatedPlcReadRequest(reader, fields, tdpu);
-        }
-
-        @Override
-        public int getTdpu() {
-            return tdpu;
-        }
-    }
-
-    protected static class CorrelatedPlcWriteRequest extends DefaultPlcWriteRequest implements CorrelatedPlcRequest {
-
-        private final int tdpu;
-
-        public CorrelatedPlcWriteRequest(PlcWriter writer, LinkedHashMap<String, FieldValueItem> fields, int tdpu) {
-            super(writer, fields);
-            this.tdpu = tdpu;
-        }
-
-        public static CorrelatedPlcWriteRequest of(PlcWriter writer, Triple<String, PlcField, PlcValue> plcValueTriple, int tdpu) {
-            LinkedHashMap<String, FieldValueItem> fields = new LinkedHashMap<>();
-            fields.put(plcValueTriple.getLeft(), new FieldValueItem(plcValueTriple.getMiddle(), plcValueTriple.getRight()));
-            return new CorrelatedPlcWriteRequest(writer, fields, tdpu);
-        }
-
-        @Override
-        public int getTdpu() {
-            return tdpu;
-        }
-    }
-
-    protected static class CorrelatedPlcSubscriptionRequest extends DefaultPlcSubscriptionRequest implements CorrelatedPlcRequest {
-
-        protected final int tdpu;
-
-        protected CorrelatedPlcSubscriptionRequest(PlcSubscriber subscriber, LinkedHashMap<String, SubscriptionPlcField> fields, int tdpu) {
-            super(subscriber, fields);
-            this.tdpu = tdpu;
-        }
-
-        protected static CorrelatedPlcSubscriptionRequest of(PlcSubscriber subscriber, Pair<String, SubscriptionPlcField> stringPlcFieldPair, int tdpu) {
-            LinkedHashMap<String, SubscriptionPlcField> fields = new LinkedHashMap<>();
-            fields.put(stringPlcFieldPair.getKey(), stringPlcFieldPair.getValue());
-            return new CorrelatedPlcSubscriptionRequest(subscriber, fields, tdpu);
-        }
-
-        @Override
-        public int getTdpu() {
-            return tdpu;
-        }
-    }
-
-    protected static class CorrelatedPlcUnsubscriptionRequest extends DefaultPlcUnsubscriptionRequest implements CorrelatedPlcRequest {
-
-        protected final int tdpu;
-
-        protected CorrelatedPlcUnsubscriptionRequest(PlcSubscriber subscriber, LinkedList<InternalPlcSubscriptionHandle> subscriptionHandles, int tdpu) {
-            super(subscriber, subscriptionHandles);
-            this.tdpu = tdpu;
-        }
-
-        protected static CorrelatedPlcUnsubscriptionRequest of(PlcSubscriber subscriber, InternalPlcSubscriptionHandle subscriptionHandle, int tdpu) {
-            LinkedList<InternalPlcSubscriptionHandle> list = new LinkedList<>();
-            list.add(subscriptionHandle);
-            return new CorrelatedPlcUnsubscriptionRequest(subscriber, list, tdpu);
-        }
-
-        @Override
-        public int getTdpu() {
-            return tdpu;
-        }
-    }
-
-    // TODO: maybe export to jmx
-    public Map<String, Number> getStatistics() {
-        HashMap<String, Number> statistics = new HashMap<>();
-        statistics.put("queue", queue.size());
-        statistics.put("sentButUnacknowledgedSubContainer", sentButUnacknowledgedSubContainer.size());
-        statistics.put("correlationToParentContainer", correlationToParentContainer.size());
-        statistics.put("containerCorrelationIdMap", containerCorrelationIdMap.size());
-        statistics.put("responsesToBeDelivered", responsesToBeDelivered.size());
-        statistics.put("correlationIdGenerator", correlationIdGenerator.get());
-        statistics.put("deliveredItems", deliveredItems.get());
-        statistics.put("erroredItems", erroredItems.get());
-        statistics.put("deliveredContainers", deliveredContainers.get());
-        statistics.put("erroredContainers", erroredContainers.get());
-        return statistics;
-    }
-
-    public static class SplitConfig {
-        private final boolean splitRead;
-        private final boolean splitWrite;
-        private final boolean splitSubscription;
-        private final boolean splitUnsubscription;
-
-        public SplitConfig() {
-            splitRead = true;
-            splitWrite = true;
-            splitSubscription = true;
-            splitUnsubscription = true;
-        }
-
-        private SplitConfig(boolean splitRead, boolean splitWrite, boolean splitSubscription, boolean splitUnsubscription) {
-            this.splitRead = splitRead;
-            this.splitWrite = splitWrite;
-            this.splitSubscription = splitSubscription;
-            this.splitUnsubscription = splitUnsubscription;
-        }
-
-        public static SplitConfigBuilder builder() {
-            return new SplitConfigBuilder();
-        }
-
-        public static class SplitConfigBuilder {
-            private boolean splitRead = true;
-            private boolean splitWrite = true;
-            private boolean splitSubscription = true;
-            private boolean splitUnsubscription = true;
-
-            public SplitConfigBuilder splitRead() {
-                splitRead = true;
-                return this;
-            }
-
-            public SplitConfigBuilder dontSplitRead() {
-                splitRead = false;
-                return this;
-            }
-
-            public SplitConfigBuilder splitWrite() {
-                splitWrite = true;
-                return this;
-            }
-
-            public SplitConfigBuilder dontSplitWrite() {
-                splitWrite = false;
-                return this;
-            }
-
-            public SplitConfigBuilder splitSubscribe() {
-                splitSubscription = true;
-                return this;
-            }
-
-            public SplitConfigBuilder dontSplitSubscribe() {
-                splitSubscription = false;
-                return this;
-            }
-
-            public SplitConfigBuilder splitUnsubscribe() {
-                splitUnsubscription = true;
-                return this;
-            }
-
-            public SplitConfigBuilder dontSplitUnsubscribe() {
-                splitUnsubscription = false;
-                return this;
-            }
-
-            public SplitConfig build() {
-                return new SplitConfig(splitRead, splitWrite, splitSubscription, splitUnsubscription);
-            }
-        }
-    }
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/request/PlcRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/request/PlcRequest.java
deleted file mode 100644
index 5c36894..0000000
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/request/PlcRequest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Handle to a Request sent via Transport Layer (usually Netty).
- */
-package org.apache.plc4x.java.spi.request;
-
-public class PlcRequest {
-
-    // void expectResponse();
-}
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/utils/XmlSerializable.java
similarity index 72%
rename from plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/utils/XmlSerializable.java
index e2adebf..0a94b85 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusIOTest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/utils/XmlSerializable.java
@@ -16,14 +16,12 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.modbus;
+package org.apache.plc4x.java.spi.utils;
 
-import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
+import org.w3c.dom.Element;
 
-public class ModbusIOTest extends ParserSerializerTestsuiteRunner {
+public interface XmlSerializable {
 
-    public ModbusIOTest() {
-        super("/protocols/modbus/ParserSerializerTestsuite.xml");
-    }
+    void xmlSerialize(Element parent);
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/IEC61131ValueHandler.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/IEC61131ValueHandler.java
similarity index 95%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/IEC61131ValueHandler.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/IEC61131ValueHandler.java
index 5f1b013..c8c9e3b 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/IEC61131ValueHandler.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/IEC61131ValueHandler.java
@@ -17,22 +17,18 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.api.value.PlcValueHandler;
 
 import java.math.BigInteger;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.nio.charset.StandardCharsets;
-import java.util.BitSet;
-import java.util.LinkedList;
-import java.util.List;
-
 
 public class IEC61131ValueHandler implements PlcValueHandler {
 
@@ -49,7 +45,6 @@ public class IEC61131ValueHandler implements PlcValueHandler {
         return newPlcValue(new Object[] {value});
     }
 
-
     public static PlcValue newPlcValue(Object[] values) {
         if (values.length == 1) {
             Object value = values[0];
@@ -77,9 +72,11 @@ public class IEC61131ValueHandler implements PlcValueHandler {
                 return new PlcDate((LocalDate) value);
             } else if (value instanceof LocalDateTime) {
                 return new PlcDateTime((LocalDateTime) value);
+            } else if (value instanceof String) {
+                return new PlcSTRING((String) value);
             } else {
                 throw new PlcUnsupportedDataTypeException("Data Type " + value.getClass()
-                    + "Is not supported");
+                    + " Is not supported");
             }
         } else {
             PlcList list = new PlcList();
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBOOL.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBOOL.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBOOL.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBOOL.java
index 022087f..120f6c1 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBOOL.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBOOL.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBYTE.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBYTE.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
index d3298e3..c368928 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBYTE.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigDecimal.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigDecimal.java
similarity index 96%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigDecimal.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigDecimal.java
index 0a52482..538a182 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigDecimal.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigDecimal.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -161,4 +162,9 @@ public class PlcBigDecimal extends PlcSimpleValue<BigDecimal> {
         return value.toString();
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigInteger.java
similarity index 96%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigInteger.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigInteger.java
index 7b5d95b..3864e71 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcBigInteger.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBigInteger.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -161,4 +162,9 @@ public class PlcBigInteger extends PlcSimpleValue<BigInteger> {
         return value.toString();
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcCHAR.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcCHAR.java
similarity index 92%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcCHAR.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcCHAR.java
index fa1fd74..dae3302 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcCHAR.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcCHAR.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -25,12 +25,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 
-import org.apache.plc4x.java.api.value.*;
-
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.LinkedList;
-import java.util.List;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
 public class PlcCHAR extends PlcIECValue<Short> {
@@ -84,7 +80,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Byte value) {
         super();
         if ((value >= minValue) && (value <= maxValue)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -96,7 +92,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Short value) {
         super();
         if ((value >= minValue) && (value <= maxValue)) {
-            this.value = (Short) value.shortValue();
+            this.value = value;
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -108,7 +104,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Integer value) {
         super();
         if ((value >= minValue) && (value <= maxValue)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -120,7 +116,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Long value) {
         super();
         if ((value >= minValue) && (value <= maxValue)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -132,7 +128,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Float value) {
         super();
         if ((value >= minValue) && (value <= maxValue) && (value % 1 == 0)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -144,7 +140,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(Double value) {
         super();
         if ((value >= minValue) && (value <= maxValue) && (value % 1 == 0)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = false;
         } else {
             throw new PlcInvalidFieldException("Value " + value +
@@ -156,7 +152,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(BigInteger value) {
         super();
         if ((value.compareTo(BigInteger.valueOf(minValue)) >= 0) && (value.compareTo(BigInteger.valueOf(maxValue)) <= 0)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = true;
         } else {
           throw new PlcInvalidFieldException("Value " + value +
@@ -168,7 +164,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     public PlcCHAR(BigDecimal value) {
         super();
         if ((value.compareTo(BigDecimal.valueOf(minValue)) >= 0) && (value.compareTo(BigDecimal.valueOf(maxValue)) <= 0) && (value.scale() <= 0)) {
-            this.value = (Short) value.shortValue();
+            this.value = value.shortValue();
             this.isNullable = true;
         } else {
           throw new PlcInvalidFieldException("Value " + value +
@@ -185,9 +181,9 @@ public class PlcCHAR extends PlcIECValue<Short> {
             if (s.length() == 0) {
                 s = " ";
             }
-            Short val = (short) s.charAt(0);
+            short val = (short) s.charAt(0);
             if ((val >= minValue) && (val <= maxValue)) {
-                this.value = (short) val;
+                this.value = val;
                 this.isNullable = false;
             } else {
                 throw new PlcInvalidFieldException("Value " + value +
@@ -224,7 +220,7 @@ public class PlcCHAR extends PlcIECValue<Short> {
     @Override
     @JsonIgnore
     public boolean getBoolean() {
-        return (value != null) && !value.equals(0);
+        return (value != null) && !value.equals((short) 0);
     }
 
     @Override
@@ -337,13 +333,13 @@ public class PlcCHAR extends PlcIECValue<Short> {
 
     @Override
     public Object getObject() {
-        return Character.toString(Character.valueOf((char) ((short) value)));
+        return Character.toString((char) ((short) value));
     }
 
     @Override
     @JsonIgnore
     public String toString() {
-        return Character.toString(Character.valueOf((char) ((short) value)));
+        return Character.toString((char) ((short) value));
     }
 
     @JsonIgnore
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDINT.java
index 62b85aa..6a7600f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDWORD.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDWORD.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
index a3cbc4b..0fba651 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDWORD.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDate.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDate.java
similarity index 91%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDate.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDate.java
index d92aea0..b04d54c 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDate.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDate.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.time.LocalDate;
 
@@ -64,4 +65,9 @@ public class PlcDate extends PlcSimpleValue<LocalDate> {
         return String.valueOf(value);
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDateTime.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDateTime.java
similarity index 93%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDateTime.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDateTime.java
index 9c98bb6..f521a5f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcDateTime.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcDateTime.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -90,4 +91,9 @@ public class PlcDateTime extends PlcSimpleValue<LocalDateTime> {
         return String.valueOf(value);
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcIECValue.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcIECValue.java
similarity index 79%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcIECValue.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcIECValue.java
index 9eeb1a7..9774f1c 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcIECValue.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcIECValue.java
@@ -17,9 +17,12 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 public abstract class PlcIECValue<T> extends PlcValueAdapter {
 
@@ -32,6 +35,7 @@ public abstract class PlcIECValue<T> extends PlcValueAdapter {
     }
 
     @Override
+    @JsonIgnore
     public Object getObject() {
         return value;
     }
@@ -74,4 +78,12 @@ public abstract class PlcIECValue<T> extends PlcValueAdapter {
         return super.getIndex(i);
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element plcValueElement = doc.createElement(getClass().getSimpleName());
+        plcValueElement.appendChild(doc.createTextNode(this.value.toString()));
+        parent.appendChild(plcValueElement);
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcINT.java
index 1e6e722..812a9cc 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLINT.java
index f188e4c..91ec4b3 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLREAL.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLREAL.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
index 31fd6c1..6684fce 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLREAL.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLWORD.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLWORD.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
index 0c0a7a4..8123818 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcLWORD.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcList.java
similarity index 74%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcList.java
index 8e912ec..9f6dbb5 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcList.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.*;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Collections;
 import java.util.List;
@@ -70,7 +71,7 @@ public class PlcList extends PlcValueAdapter {
     }
 
     @Override
-    @JsonIgnore
+    @JsonInclude()
     public PlcValue getIndex(int i) {
         return listItems.get(i);
     }
@@ -87,4 +88,17 @@ public class PlcList extends PlcValueAdapter {
         return "[" + listItems.stream().map(PlcValue::toString).collect(Collectors.joining(",")) + "]";
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element plcValueElement = doc.createElement("PlcList");
+        parent.appendChild(plcValueElement);
+        for (PlcValue listItem : listItems) {
+            if(!(listItem instanceof XmlSerializable)) {
+                throw new RuntimeException("Error serializing. List item doesn't implement XmlSerializable");
+            }
+            ((XmlSerializable) listItem).xmlSerialize(plcValueElement);
+        }
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcNull.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcNull.java
similarity index 97%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcNull.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcNull.java
index 24c8bc7..22a344a 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcNull.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcNull.java
@@ -16,7 +16,9 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
+
+import org.apache.plc4x.java.api.value.PlcValue;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcREAL.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
similarity index 96%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcREAL.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
index 945a3d8..7827cfd 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcREAL.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
@@ -17,12 +17,9 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.*;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 
 import java.math.BigDecimal;
@@ -224,7 +221,7 @@ public class PlcREAL extends PlcIECValue<Float> {
     }
 
     @Override
-    @JsonIgnore
+    @JsonInclude
     public float getFloat() {
         return value;
     }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSINT.java
index 8288f30..35968b1 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSTRING.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSTRING.java
similarity index 96%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSTRING.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSTRING.java
index 7ee4efc..714cddb 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSTRING.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSTRING.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -229,4 +230,9 @@ public class PlcSTRING extends PlcSimpleValue<String> {
         return "\"" + value + "\"";
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSimpleValue.java
similarity index 95%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSimpleValue.java
index ea49a0a..87e805a 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcSimpleValue.java
@@ -17,9 +17,10 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.plc4x.java.api.value.PlcValue;
 
 public abstract class PlcSimpleValue<T> extends PlcValueAdapter {
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
similarity index 70%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
index 929a62b..eb2a202 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
@@ -17,12 +17,16 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Collections;
 import java.util.Map;
@@ -81,4 +85,21 @@ public class PlcStruct extends PlcValueAdapter {
         return "{" + map.entrySet().stream().map(entry -> String.format("\"%s\": %s", entry.getKey(), entry.getValue())).collect(Collectors.joining(",")) + "}";
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element plcValueElement = doc.createElement("PlcStruct");
+        parent.appendChild(plcValueElement);
+        for (Map.Entry<String, PlcValue> entry : map.entrySet()) {
+            String fieldName = entry.getKey();
+            Element fieldElement = doc.createElement(fieldName);
+            plcValueElement.appendChild(fieldElement);
+            PlcValue fieldValue = entry.getValue();
+            if(!(fieldValue instanceof XmlSerializable)) {
+                throw new RuntimeException("Error serializing. List item doesn't implement XmlSerializable");
+            }
+            ((XmlSerializable) fieldValue).xmlSerialize(fieldElement);
+        }
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcTime.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTime.java
similarity index 91%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcTime.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTime.java
index b4b2f9d..3de9704 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcTime.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTime.java
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.w3c.dom.Element;
 
 import java.time.LocalTime;
 
@@ -64,4 +65,9 @@ public class PlcTime extends PlcSimpleValue<LocalTime> {
         return String.valueOf(value);
     }
 
+    @Override
+    public void xmlSerialize(Element parent) {
+        // TODO: Implement
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUDINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUDINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUDINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUDINT.java
index 5f71bac..a132741 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUDINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUDINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUINT.java
index c86ccdf..ab1c7c6 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcULINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcULINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcULINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcULINT.java
index 1273bb4..e9907d3 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcULINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcULINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUSINT.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUSINT.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUSINT.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUSINT.java
index 3316c97..00d186f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcUSINT.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcUSINT.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValueAdapter.java
similarity index 96%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValueAdapter.java
index f9a7daa..0ab64e9 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValueAdapter.java
@@ -16,10 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -30,7 +32,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-public class PlcValueAdapter implements PlcValue {
+public abstract class PlcValueAdapter implements PlcValue, XmlSerializable {
 
     @Override
     public Object getObject() {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValues.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValues.java
similarity index 97%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValues.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValues.java
index 39e2eed..708249f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValues.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcValues.java
@@ -17,9 +17,10 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException;
+import org.apache.plc4x.java.api.value.PlcValue;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWCHAR.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWCHAR.java
similarity index 99%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWCHAR.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWCHAR.java
index ec7028e..8c1d98d 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWCHAR.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWCHAR.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWORD.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
similarity index 98%
rename from plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWORD.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
index eb87609..7cd1f95 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcWORD.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
@@ -17,13 +17,15 @@
  * under the License.
  */
 
-package org.apache.plc4x.java.api.value;
+package org.apache.plc4x.java.spi.values;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
diff --git a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/ConnectedEntityTest.java b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/ConnectedEntityTest.java
index 24725b4..410a11d 100644
--- a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/ConnectedEntityTest.java
+++ b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/ConnectedEntityTest.java
@@ -21,7 +21,7 @@ package org.apache.plc4x.java.opm;
 
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcSTRING;
+import org.apache.plc4x.java.spi.values.PlcSTRING;
 import org.apache.plc4x.java.mock.connection.MockConnection;
 import org.apache.plc4x.java.mock.connection.MockDevice;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
diff --git a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerComplexTest.java b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerComplexTest.java
index f4d41a2..5957380 100644
--- a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerComplexTest.java
+++ b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerComplexTest.java
@@ -28,16 +28,16 @@ import org.apache.plc4x.java.api.metadata.PlcConnectionMetadata;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
-import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.InternalPlcWriteRequest;
 import org.apache.plc4x.java.spi.messages.PlcReader;
 import org.apache.plc4x.java.spi.messages.PlcWriter;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
+import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.PlcDINT;
+import org.apache.plc4x.java.spi.values.PlcLINT;
 import org.assertj.core.api.WithAssertions;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -226,7 +226,7 @@ public class PlcEntityManagerComplexTest implements WithAssertions {
                     Function.identity(),
                     s -> new ResponseItem<>(PlcResponseCode.OK, Objects.requireNonNull(responses.get(s), s + " not found"))
                 ));
-            return CompletableFuture.completedFuture(new DefaultPlcReadResponse((InternalPlcReadRequest) readRequest, map));
+            return CompletableFuture.completedFuture(new DefaultPlcReadResponse(readRequest, map));
         };
         when(connection.readRequestBuilder()).then(invocation -> new DefaultPlcReadRequest.Builder(reader, getFieldHandler()));
         PlcWriter writer = writeRequest -> {
@@ -235,7 +235,7 @@ public class PlcEntityManagerComplexTest implements WithAssertions {
                     Function.identity(),
                     s -> PlcResponseCode.OK
                 ));
-            return CompletableFuture.completedFuture(new DefaultPlcWriteResponse((InternalPlcWriteRequest) writeRequest, map));
+            return CompletableFuture.completedFuture(new DefaultPlcWriteResponse(writeRequest, map));
         };
         when(connection.writeRequestBuilder()).then(invocation -> new DefaultPlcWriteRequest.Builder(writer, getFieldHandler(), getValueHandler()));
 
@@ -246,11 +246,11 @@ public class PlcEntityManagerComplexTest implements WithAssertions {
         return new NoOpPlcFieldHandler();
     }
 
-    private PlcFieldHandler getValueHandler() {
-        return new NoOpPlcFieldHandler();
+    private PlcValueHandler getValueHandler() {
+        return new NoOpPlcValueHandler();
     }
 
-    private static class NoOpPlcFieldHandler extends DefaultPlcFieldHandler {
+    private static class NoOpPlcFieldHandler implements PlcFieldHandler {
         @Override
         public org.apache.plc4x.java.api.model.PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
             return new org.apache.plc4x.java.api.model.PlcField() {
@@ -258,11 +258,15 @@ public class PlcEntityManagerComplexTest implements WithAssertions {
         }
     }
 
-    private static class NoOpPlcValueHandler extends IEC61131Valuehandler {
+    private static class NoOpPlcValueHandler implements PlcValueHandler {
+        @Override
+        public PlcValue of(Object value) {
+            throw new RuntimeException("Data Type " + value.getClass().getSimpleName() + "Is not supported");
+        }
+
         @Override
-        public org.apache.plc4x.java.api.model.PlcValue newPlcValue(PlcField field, Object value) throws PlcUnsuppportedDataTypeException {
-            throw PlcUnsuppportedDataTypeException("Data Type " + field.getPlcDataType())
-                + "Is not supported");
+        public PlcValue of(Object[] values) {
+            throw new RuntimeException("Data Type " + values.getClass().getSimpleName() + "Is not supported");
         }
     }
 
diff --git a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
index bf7be56..03f093c 100644
--- a/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
+++ b/plc4j/tools/opm/src/test/java/org/apache/plc4x/java/opm/PlcEntityManagerTest.java
@@ -24,7 +24,7 @@ import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcSTRING;
+import org.apache.plc4x.java.spi.values.PlcSTRING;
 import org.apache.plc4x.java.mock.connection.MockConnection;
 import org.apache.plc4x.java.mock.connection.MockDevice;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
diff --git a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTaskTest.java b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTaskTest.java
index c0390b0..2332769 100644
--- a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTaskTest.java
+++ b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTaskTest.java
@@ -22,7 +22,7 @@ package org.apache.plc4x.java.scraper;
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcSTRING;
+import org.apache.plc4x.java.spi.values.PlcSTRING;
 import org.apache.plc4x.java.mock.connection.MockConnection;
 import org.apache.plc4x.java.mock.connection.MockDevice;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
diff --git a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTest.java b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTest.java
index 2d5fe4a..edd59e5 100644
--- a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTest.java
+++ b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/ScraperTest.java
@@ -25,7 +25,7 @@ import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcDINT;
+import org.apache.plc4x.java.spi.values.PlcDINT;
 import org.apache.plc4x.java.mock.connection.MockConnection;
 import org.apache.plc4x.java.mock.connection.MockDevice;
 import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
diff --git a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/triggeredscraper/TriggeredScraperImplTest.java b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/triggeredscraper/TriggeredScraperImplTest.java
index 7f222bd..d9ccbe2 100644
--- a/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/triggeredscraper/TriggeredScraperImplTest.java
+++ b/plc4j/tools/scraper/src/test/java/org/apache/plc4x/java/scraper/triggeredscraper/TriggeredScraperImplTest.java
@@ -21,8 +21,8 @@ package org.apache.plc4x.java.scraper.triggeredscraper;
 
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.PlcBOOL;
-import org.apache.plc4x.java.api.value.PlcLINT;
+import org.apache.plc4x.java.spi.values.PlcBOOL;
+import org.apache.plc4x.java.spi.values.PlcLINT;
 import org.apache.plc4x.java.mock.connection.MockConnection;
 import org.apache.plc4x.java.mock.connection.MockDevice;
 import org.apache.plc4x.java.scraper.config.ScraperConfiguration;
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
index a591515..b4fce42 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
@@ -35,6 +35,7 @@ import org.apache.plc4x.java.api.messages.PlcResponse;
 import org.apache.plc4x.java.spi.connection.ChannelExposingConnection;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
 import org.apache.plc4x.test.driver.exceptions.DriverTestsuiteException;
 import org.apache.plc4x.test.driver.model.DriverTestsuite;
 import org.apache.plc4x.test.driver.model.StepType;
@@ -56,8 +57,15 @@ import org.slf4j.LoggerFactory;
 import org.xmlunit.builder.DiffBuilder;
 import org.xmlunit.diff.Diff;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.StringWriter;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -272,7 +280,7 @@ public class DriverTestsuiteRunner {
 
                     // Reset the future.
                     responseFuture = null;
-                    final String serializedResponse = mapper.writeValueAsString(plcResponse);
+                    final String serializedResponse = serializeToXmlString((XmlSerializable) plcResponse);
                     validateApiMessage(payload, serializedResponse);
 
                     break;
@@ -444,4 +452,31 @@ public class DriverTestsuiteRunner {
         }
     }
 
+    private String serializeToXmlString(XmlSerializable value) {
+        try {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+            DocumentBuilder builder = dbf.newDocumentBuilder();
+            org.w3c.dom.Document doc = builder.newDocument();
+            org.w3c.dom.Element root = doc.createElement("root");
+            doc.appendChild(root);
+            value.xmlSerialize(root);
+            DOMSource domSource = new DOMSource(doc.getDocumentElement().getFirstChild());
+            StringWriter writer = new StringWriter();
+            StreamResult result = new StreamResult(writer);
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer transformer = tf.newTransformer();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+            transformer.setOutputProperty("omit-xml-declaration", "yes");
+            transformer.transform(domSource, result);
+            return writer.toString();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        } catch (TransformerConfigurationException e) {
+            throw new RuntimeException(e);
+        } catch (TransformerException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }
diff --git a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
index e57816c..1b3805e 100644
--- a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
+++ b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
@@ -145,21 +145,25 @@
         </AmsTCPPacket>
       </incoming-plc-message>
       <api-response name="Report Read Response to application">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz className="org.apache.plc4x.java.ads.field.DirectAdsField">
-              <indexGroup>4040</indexGroup>
-              <indexOffset>8</indexOffset>
-              <adsDataType>BOOL</adsDataType>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz>
+                <DirectAdsField>
+                  <indexGroup>4040</indexGroup>
+                  <indexOffset>8</indexOffset>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </DirectAdsField>
+              </hurz>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz result="OK">
+              <PlcBOOL>true</PlcBOOL>
             </hurz>
-          </request>
-          <hurz>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>true</object>
-            </value>
-          </hurz>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
       <delay>1000</delay>
     </steps>
@@ -285,32 +289,36 @@
         </AmsTCPPacket>
       </incoming-plc-message>
       <api-response name="Report Read Response to application">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz1 className="org.apache.plc4x.java.ads.field.DirectAdsField">
-              <indexGroup>4040</indexGroup>
-              <indexOffset>8</indexOffset>
-              <adsDataType>BOOL</adsDataType>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz1>
+                <DirectAdsField>
+                  <indexGroup>4040</indexGroup>
+                  <indexOffset>8</indexOffset>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </DirectAdsField>
+              </hurz1>
+              <hurz2>
+                <DirectAdsField>
+                  <indexGroup>4040</indexGroup>
+                  <indexOffset>12</indexOffset>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </DirectAdsField>
+              </hurz2>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz1 result="OK">
+              <PlcBOOL>true</PlcBOOL>
             </hurz1>
-            <hurz2 className="org.apache.plc4x.java.ads.field.DirectAdsField">
-              <indexGroup>4040</indexGroup>
-              <indexOffset>12</indexOffset>
-              <adsDataType>BOOL</adsDataType>
+            <hurz2 result="OK">
+              <PlcBOOL>true</PlcBOOL>
             </hurz2>
-          </request>
-          <hurz1>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>true</object>
-            </value>
-          </hurz1>
-          <hurz2>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>true</object>
-            </value>
-          </hurz2>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
       <delay>1000</delay>
     </steps>
@@ -507,20 +515,24 @@
         </AmsTCPPacket>
       </incoming-plc-message>
       <api-response name="Report Read Response to application">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz1 className="org.apache.plc4x.java.ads.field.SymbolicAdsField">
-              <adsDataType>BOOL</adsDataType>
-              <symbolicField>main.f_trigDateiGelesen.M</symbolicField>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz1>
+                <SymbolicAdsField>
+                  <symbolicAddress>main.f_trigDateiGelesen.M</symbolicAddress>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </SymbolicAdsField>
+              </hurz1>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz1 result="OK">
+              <PlcBOOL>false</PlcBOOL>
             </hurz1>
-          </request>
-          <hurz1>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>false</object>
-            </value>
-          </hurz1>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
     </steps>
   </testcase>
@@ -716,20 +728,24 @@
         </AmsTCPPacket>
       </incoming-plc-message>
       <api-response name="Report Read Response to application">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz1 className="org.apache.plc4x.java.ads.field.SymbolicAdsField">
-              <adsDataType>BOOL</adsDataType>
-              <symbolicField>main.f_trigDateiGelesen.M</symbolicField>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz1>
+                <SymbolicAdsField>
+                  <symbolicAddress>main.f_trigDateiGelesen.M</symbolicAddress>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </SymbolicAdsField>
+              </hurz1>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz1 result="OK">
+              <PlcBOOL>false</PlcBOOL>
             </hurz1>
-          </request>
-          <hurz1>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>false</object>
-            </value>
-          </hurz1>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
       <delay>500</delay>
       <api-request name="Receive a second Read Request for the same resource from application">
@@ -828,20 +844,24 @@
         </AmsTCPPacket>
       </incoming-plc-message>
       <api-response name="Report Read Response to application again">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz1 className="org.apache.plc4x.java.ads.field.SymbolicAdsField">
-              <adsDataType>BOOL</adsDataType>
-              <symbolicField>main.f_trigDateiGelesen.M</symbolicField>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz1>
+                <SymbolicAdsField>
+                  <symbolicAddress>main.f_trigDateiGelesen.M</symbolicAddress>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>BOOL</dataType>
+                </SymbolicAdsField>
+              </hurz1>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz1 result="OK">
+              <PlcBOOL>false</PlcBOOL>
             </hurz1>
-          </request>
-          <hurz1>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcBOOL">
-              <object>false</object>
-            </value>
-          </hurz1>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
     </steps>
   </testcase>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/DriverTestsuite.xml b/protocols/modbus/src/test/resources/protocols/modbus/DriverTestsuite.xml
index befd271..1dd995f 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/DriverTestsuite.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/DriverTestsuite.xml
@@ -108,6 +108,69 @@
           <fields>
             <field className="org.apache.plc4x.test.driver.model.api.TestField">
               <name>hurz</name>
+              <address>holding-register:1:REAL</address>
+            </field>
+          </fields>
+        </TestReadRequest>
+      </api-request>
+      <outgoing-plc-message name="Send Modbus Input-Register Read Request">
+        <!-- 000a00000006010300000004 -->
+        <parser-arguments>
+          <response>false</response>
+        </parser-arguments>
+        <ModbusTcpADU className="org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU">
+          <transactionIdentifier>1</transactionIdentifier>
+          <unitIdentifier>1</unitIdentifier>
+          <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUReadHoldingRegistersRequest">
+            <startingAddress>0</startingAddress>
+            <quantity>2</quantity>
+          </pdu>
+        </ModbusTcpADU>
+      </outgoing-plc-message>
+      <incoming-plc-message name="Receive Modbus Input-Register Read Response">
+        <!-- 000b0000000b0103080000000000000000 -->
+        <parser-arguments>
+          <response>true</response>
+        </parser-arguments>
+        <ModbusTcpADU className="org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU">
+          <transactionIdentifier>1</transactionIdentifier>
+          <unitIdentifier>1</unitIdentifier>
+          <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUReadHoldingRegistersResponse">
+            <value>QEkP20BJD9s=</value>
+          </pdu>
+        </ModbusTcpADU>
+      </incoming-plc-message>
+      <api-response name="Report Read Response to application">
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz>
+                <ModbusFieldHoldingRegister>
+                  <address>0</address>
+                  <numberOfElements>1</numberOfElements>
+                  <dataType>IEC61131_REAL</dataType>
+                </ModbusFieldHoldingRegister>
+              </hurz>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz result="OK">
+              <PlcREAL>3.1415927</PlcREAL>
+            </hurz>
+          </values>
+        </PlcReadResponse>
+      </api-response>
+    </steps>
+  </testcase>
+
+  <testcase>
+    <name>Array element read request</name>
+    <steps>
+      <api-request name="Receive Read Request from application">
+        <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
+          <fields>
+            <field className="org.apache.plc4x.test.driver.model.api.TestField">
+              <name>hurz</name>
               <address>holding-register:1:REAL[2]</address>
             </field>
           </fields>
@@ -141,33 +204,27 @@
         </ModbusTcpADU>
       </incoming-plc-message>
       <api-response name="Report Read Response to application">
-        <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
-          <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
-            <hurz className="org.apache.plc4x.java.modbus.field.ModbusFieldHoldingRegister">
-              <address>0</address>
-              <dataType>IEC61131_REAL</dataType>
-              <lengthWords>4</lengthWords>
-              <dataTypeSize>4</dataTypeSize>
-              <lengthBytes>8</lengthBytes>
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz>
+                <ModbusFieldHoldingRegister>
+                  <address>0</address>
+                  <numberOfElements>2</numberOfElements>
+                  <dataType>IEC61131_REAL</dataType>
+                </ModbusFieldHoldingRegister>
+              </hurz>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz result="OK">
+              <PlcList>
+                <PlcREAL>3.1415927</PlcREAL>
+                <PlcREAL>3.1415927</PlcREAL>
+              </PlcList>
             </hurz>
-          </request>
-          <hurz>
-            <code>OK</code>
-            <value className="org.apache.plc4x.java.api.value.PlcList">
-              <object>java.util.Collections..UnmodifiableRandomAccessList</object>
-              <object>org.apache.plc4x.java.api.value.PlcREAL</object>
-              <object>
-                <object>java.lang.Float</object>
-                <object>3.1415927</object>
-              </object>
-              <object>org.apache.plc4x.java.api.value.PlcREAL</object>
-              <object>
-                <object>java.lang.Float</object>
-                <object>3.1415927</object>
-              </object>
-            </value>
-          </hurz>
-        </DefaultPlcReadResponse>
+          </values>
+        </PlcReadResponse>
       </api-response>
     </steps>
   </testcase>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/ParserSerializerTestsuite.xml b/protocols/modbus/src/test/resources/protocols/modbus/ParserSerializerTestsuite.xml
index ccef65b..3dd0c83 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/ParserSerializerTestsuite.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/ParserSerializerTestsuite.xml
@@ -42,7 +42,9 @@
 
   <testcase>
     <name>Read Input Registers Response</name>
-    <raw>7cfe000000c9ff04c600000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000004000000000000000000000000000001db000001d600004a380000000000000000000000000000000000000000000000000000000000006461696d006e0000000000000000000000000000303100300000000000000000000000000000000000000000000000000000000000000000000000000000</raw>
+    <raw>
+      7cfe000000c9ff04c600000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000004000000000000000000000000000001db000001d600004a380000000000000000000000000000000000000000000000000000000000006461696d006e0000000000000000000000000000303100300000000000000000000000000000000000000000000000000000000000000000000000000000
+    </raw>
     <root-type>ModbusTcpADU</root-type>
     <parser-arguments>
       <response>true</response>
@@ -132,14 +134,14 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</value>
         <transactionIdentifier>10</transactionIdentifier>
         <unitIdentifier>1</unitIdentifier>
         <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUWriteFileRecordRequest">
... 665 lines suppressed ...