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 2019/02/11 15:15:58 UTC

[incubator-plc4x] branch develop updated: - Finished a fist version of the dynamic driver that is able to read a single item from a remote S7 device. - Placed the word "Eventually" with something that comes closer to the german "Eventuell"

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

cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new e3cb295  - Finished a fist version of the dynamic driver that is able to read a single item from a remote S7 device. - Placed the word "Eventually" with something that comes closer to the german "Eventuell"
e3cb295 is described below

commit e3cb295d7db694285dc9d2f6f326d19f9b066b9f
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Feb 11 16:15:54 2019 +0100

    - Finished a fist version of the dynamic driver that is able to read a single item from a remote S7 device.
    - Placed the word "Eventually" with something that comes closer to the german "Eventuell"
---
 .../plc4x/java/api/types/PlcResponseCode.java      |   1 +
 .../ethernetip/netty/Plc4XEtherNetIpProtocol.java  |   2 +-
 .../org/apache/plc4x/java/s7/netty/S7Protocol.java |   4 +-
 .../java/s7/netty/model/types/TransportSize.java   |   4 +-
 .../asciidoc/developers/implementing-drivers.adoc  |   2 +-
 .../apache/plc4x/protocols/s7/protocol.scxml.xml   | 192 ++++++-
 sandbox/dynamic-driver-base/pom.xml                |   5 +
 .../java/dynamic/actions/BasePlc4xAction.java      |   2 +-
 .../java/dynamic/actions/InitContextAction.java    |  17 +
 .../java/dynamic/actions/ReceiveAction.java        |  83 +--
 .../actions/ReceiveExtractVerifyAction.java        | 114 +++++
 .../java/dynamic/actions/ReceiveRequestAction.java |  52 ++
 .../dynamic/actions/ReceiveResponseAction.java     |  65 +++
 .../sandbox/java/dynamic/actions/SendAction.java   |  37 +-
 .../java/dynamic/actions/SendRequestAction.java    |  57 +++
 .../connection/DynamicDriverConnectionBase.java    |  35 +-
 .../java/dynamic/utils/RequestRegistry.java        |  66 +++
 ...ter.scala => JDOMTemplateInfosetInputter.scala} |  17 +-
 sandbox/dynamic-driver-s7/pom.xml                  |   6 +-
 .../sandbox/java/dynamic/s7/DynamicS7Driver.java   |   9 +-
 .../apache/plc4x/sandbox/java/dynamic/s7/Poc.java  | 102 ----
 .../s7/actions/S7DecodeReadResponseAction.java     | 315 ++++++++++++
 .../s7/actions/S7DecodeWriteResponseAction.java    |  34 ++
 .../dynamic/s7/connection/DynamicS7Connection.java |  55 +-
 .../dynamic/s7/types/DataTransportErrorCode.java   |  62 +++
 .../java/dynamic/s7/types/DataTransportSize.java   |  64 +++
 .../sandbox/java/dynamic/s7/types/MemoryArea.java  |  83 +++
 .../java/dynamic/s7/types/S7ControllerType.java    |  30 ++
 .../java/dynamic/s7}/types/TransportSize.java      |   8 +-
 .../sandbox/java/dynamic/s7/utils/S7Field.java     | 194 +++++++
 .../java/dynamic/s7/utils/S7PlcFieldHandler.java   | 569 +++++++++++++++++++++
 .../protocols/delta-v/reverse-engineering.adoc     |   2 +-
 src/site/asciidoc/protocols/s7/s7comm-plus.adoc    |   2 +-
 33 files changed, 2039 insertions(+), 251 deletions(-)

diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcResponseCode.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcResponseCode.java
index b72018f..dbd4be5 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcResponseCode.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/types/PlcResponseCode.java
@@ -22,6 +22,7 @@ public enum PlcResponseCode {
 
     OK,
     NOT_FOUND,
+    ACCESS_DENIED,
     INVALID_ADDRESS,
     INVALID_DATATYPE,
     INTERNAL_ERROR,
diff --git a/plc4j/protocols/ethernet-ip/src/main/java/org/apache/plc4x/java/ethernetip/netty/Plc4XEtherNetIpProtocol.java b/plc4j/protocols/ethernet-ip/src/main/java/org/apache/plc4x/java/ethernetip/netty/Plc4XEtherNetIpProtocol.java
index eb47b91..1dea06e 100644
--- a/plc4j/protocols/ethernet-ip/src/main/java/org/apache/plc4x/java/ethernetip/netty/Plc4XEtherNetIpProtocol.java
+++ b/plc4j/protocols/ethernet-ip/src/main/java/org/apache/plc4x/java/ethernetip/netty/Plc4XEtherNetIpProtocol.java
@@ -74,7 +74,7 @@ public class Plc4XEtherNetIpProtocol extends MessageToMessageCodec<EnipPacket, P
     // In CIP we are doing explicit connected messaging, this requires every used address to be registered at the
     // remote server and to use that Addresses connectionId for accessing data. We are saving the references to
     // these here.
-    // REMARK: Eventually we should add a timeout to these so we unregister them after not being used
+    // REMARK: Perhaps we should add a timeout to these so we unregister them after not being used
     // for quire some time. Hereby freeing resources on both client and server.
     private Map<PlcField, Long> fieldConnectionMap = new ConcurrentHashMap<>();
 
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
index 12759e2..787b200 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
@@ -501,7 +501,7 @@ public class S7Protocol extends ChannelDuplexHandler {
                     }
                 }
 
-                // Eventually send the next message (if there is one).
+                // Try to send the next message (if there is one).
                 trySendingMessages(ctx);
             }
 
@@ -808,7 +808,7 @@ public class S7Protocol extends ChannelDuplexHandler {
 
                     logger.debug("S7 Message with id {} sent", s7RequestMessage.getTpduReference());
                 }
-                // TODO: Eventually remove this.
+                // TODO: Perhaps remove this.
                 break;
             } else {
                 break;
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
index 6de428d..98f35d6 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
@@ -103,12 +103,12 @@ public enum TransportSize {
     // Single-byte character
     CHAR(0x03, "B", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY),
     // Double-byte character
-    // TODO: Find the code (Eventually 0x13)
+    // TODO: Find the code (Perhaps 0x13)
     WCHAR(0x13, "X", 2, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500),
     // Variable-length single-byte character string
     STRING(0x03, "X", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY),
     // Variable-length double-byte character string
-    // TODO: Find the code (Eventually 0x13)
+    // TODO: Find the code (Perhaps 0x13)
     WSTRING(0x00, "X", 1, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500);
 
     /* TO BE CONTINUED */
diff --git a/plc4j/protocols/src/site/asciidoc/developers/implementing-drivers.adoc b/plc4j/protocols/src/site/asciidoc/developers/implementing-drivers.adoc
index bed4d3c..899f796 100644
--- a/plc4j/protocols/src/site/asciidoc/developers/implementing-drivers.adoc
+++ b/plc4j/protocols/src/site/asciidoc/developers/implementing-drivers.adoc
@@ -155,7 +155,7 @@ Also as creating of raw sockets requires elevated user permissions the applicati
 
 When setup correctly the raw socket connector allows implementing protocols right down to manually constructing `Ehternet` frames.
 
-This is currently treated as a temporary solution as we have to collect experience with this approach. Eventually native transports implemented as part of the PLC4X project might be the more performant solution.
+This is currently treated as a temporary solution as we have to collect experience with this approach. Perhaps native transports implemented as part of the PLC4X project might be the more performant solution.
 
 === Serial
 
diff --git a/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.scxml.xml b/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.scxml.xml
index eba7511..da741d4 100644
--- a/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.scxml.xml
+++ b/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.scxml.xml
@@ -37,6 +37,9 @@
     <sc:data id="s7PduLength"/>
     <sc:data id="s7ArticleNumber"/>
     <sc:data id="plcType"/>
+
+    <!-- Data container for processing requests -->
+    <sc:data id="container"/>
   </sc:datamodel>
 
   <!--
@@ -44,8 +47,11 @@
   -->
   <sc:state id="init">
     <sc:onentry>
-      <!-- Setup the initial content of the connection context (Callback in the driver) -->
-      <plc4x:initContext protocolDaffodilSchemaName="protocolDaffodilSchema"/>
+      <!--
+        Setup the initial content of the connection context (Callback in the driver)
+        (4294967295 is the max unsigned int value)
+      -->
+      <plc4x:initContext maxRequestId="4294967295" protocolDaffodilSchemaName="protocolDaffodilSchema"/>
     </sc:onentry>
     <sc:transition event="success" target="connect">
       <sc:assign location="args" expr="_event.data"/>
@@ -137,13 +143,13 @@
     -->
     <sc:state id="receiveCotpConnectionResponse">
       <sc:onentry>
-        <plc4x:receive timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
+        <plc4x:receiveExtractVerify timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
           <verification name="cotpLocalReference" xpath-expression="/s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/destinationReference/text()[1]"/>
           <extraction name="cotpRemoteReference" xpath-expression="/s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/sourceReference/text()[1]"/>
           <extraction name="cotpTpduSize" xpath-expression="/s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterTpduSize/tpduSize/text()[1]"/>
           <extraction name="cotpCallingTsap" xpath-expression="/s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterCallingTsap/tsapId/text()[1]"/>
           <extraction name="cotpCalledTsap" xpath-expression="/s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterCalledTsap/tsapId/text()[1]"/>
-        </plc4x:receive>
+        </plc4x:receiveExtractVerify>
       </sc:onentry>
       <sc:transition event="success" target="sendS7SetupCommunicationRequest"/>
       <sc:transition event="failure" target="error"/>
@@ -216,12 +222,12 @@
     -->
     <sc:state id="receiveS7SetupCommunicationResponse">
       <sc:onentry>
-        <plc4x:receive timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
+        <plc4x:receiveExtractVerify timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
           <extraction name="returnCode" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/errorCode/text()[1]"/>
           <extraction name="s7MaxAmqCaller" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/parameter/s7:S7GeneralParameterSetupCommunication/maxAmqCaller/text()[1]"/>
           <extraction name="s7MaxAmqCallee" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/parameter/s7:S7GeneralParameterSetupCommunication/maxAmqCallee/text()[1]"/>
           <extraction name="s7PduLength" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/parameter/s7:S7GeneralParameterSetupCommunication/pduLength/text()[1]"/>
-        </plc4x:receive>
+        </plc4x:receiveExtractVerify>
       </sc:onentry>
       <sc:transition event="success" cond="plcType == null" target="sendS7IdentificationRequest"/>
       <sc:transition event="success" cond="plcType != null" target="connected"/>
@@ -253,7 +259,7 @@
                 <type>7</type>
                 <s7:S7UserDataMessage>
                   <reserved>0</reserved>
-                  <tpduReference>256</tpduReference>
+                  <tpduReference>1</tpduReference>
                   <parametersLength>8</parametersLength>
                   <payloadsLength>8</payloadsLength>
                   <parameters>
@@ -299,15 +305,16 @@
     -->
     <sc:state id="receiveS7IdentificationRequest">
       <sc:onentry>
-        <plc4x:receive timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
+        <plc4x:receiveExtractVerify timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2">
           <!-- Ensure everything is ok -->
           <!--verification value="255" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7UserDataMessage/payloads/payload/s7:S7UserDataPayloadCpuServices/returnCode/text()"/-->
           <!-- Extract the article-number of the SslDataRecordModuleIdentification with the index 1 -->
           <extraction name="s7ArticleNumber" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7UserDataMessage/payloads/payload/s7:S7UserDataPayloadCpuServices/partialList/sslDataRecords/sslDataRecord//s7:S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification[index='1']/articleNumber/text()"/>
-        </plc4x:receive>
+        </plc4x:receiveExtractVerify>
       </sc:onentry>
       <sc:transition event="success" target="connected">
         <plc4x:S7DecodeArticleNumber articleNumberParameterName="s7ArticleNumber" plcTypeParameterName="plcType"/>
+        <sc:log expr="'Connected to PLC of type: ' + plcType"/>
       </sc:transition>
       <sc:transition event="failure" target="error"/>
       <sc:transition event="disconnect" target="disconnect"/>
@@ -317,9 +324,174 @@
       Default state after connecting to a PLC.
     -->
     <sc:state id="connected">
+      <sc:transition event="read" target="sendS7ReadRequest">
+        <sc:assign location="container" expr="_event.data"/>
+      </sc:transition>
+      <sc:transition event="write" target="sendS7WriteRequest">
+        <sc:assign location="container" expr="_event.data"/>
+      </sc:transition>
+      <sc:transition event="disconnect" target="disconnect"/>
+    </sc:state>
+
+    <sc:state id="sendS7ReadRequest">
+      <sc:datamodel>
+        <sc:data id="requestId"/>
+      </sc:datamodel>
       <sc:onentry>
-        <sc:log expr="'Connected to PLC of type: ' + plcType"/>
+        <plc4x:sendRequest idExpression="/s7:TpktMessage/userData/userData/s7:S7RequestMessage/tpduReference/text()">
+          <s7:TpktMessage>
+            <magicByte>3</magicByte>
+            <reserved>0</reserved>
+            <length>31</length>
+            <userData>
+              <headerLength>2</headerLength>
+              <type>240</type>
+              <s7:CotpTpduData>
+                <endOfTransmission>1</endOfTransmission>
+                <tpduRef>0</tpduRef>
+              </s7:CotpTpduData>
+              <userData>
+                <magicByte>50</magicByte>
+                <type>1</type>
+                <s7:S7RequestMessage>
+                  <reserved>0</reserved>
+                  <tpduReference>${requestId}</tpduReference>
+                  <parametersLength>14</parametersLength>
+                  <payloadsLength>0</payloadsLength>
+                  <parameters>
+                    <parameter>
+                      <type>4</type>
+                      <s7:S7RequestParameterReadVar>
+                        <numItems>1</numItems>
+                        <items>
+                          <item>
+                            <type>18</type>
+                            <s7:S7RequestParameterReadVarAnyItem>
+                              <paramLength>10</paramLength>
+                              <addressingMode>16</addressingMode>
+                              <dataType>${container.request.fields[0].dataType.typeCode}</dataType><!--8 ${s7ReadDataType}-->
+                              <numElements>${container.request.fields[0].numElements}</numElements><!--1 ${s7ReadNumElements}-->
+                              <dataBlockNumber>${container.request.fields[0].blockNumber}</dataBlockNumber><!--0 ${s7ReadDataBlockNumber}-->
+                              <memoryArea>${container.request.fields[0].memoryArea.code}</memoryArea><!--131 ${s7ReadMemoryArea}-->
+                              <byteOffset>${container.request.fields[0].byteOffset}</byteOffset><!--16 ${s7ReadByteOffset}-->
+                              <bitOffset>${container.request.fields[0].bitOffset}</bitOffset><!--0 ${s7ReadBitOffset}-->
+                            </s7:S7RequestParameterReadVarAnyItem>
+                          </item>
+                        </items>
+                      </s7:S7RequestParameterReadVar>
+                    </parameter>
+                  </parameters>
+                  <payloads>
+                    <payload>
+                      <s7:S7RequestPayloadReadVar/>
+                    </payload>
+                  </payloads>
+                </s7:S7RequestMessage>
+              </userData>
+            </userData>
+          </s7:TpktMessage>
+        </plc4x:sendRequest>
+      </sc:onentry>
+      <sc:transition event="success" target="receiveS7ReadResponse"/>
+      <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
+    </sc:state>
+
+    <sc:state id="receiveS7ReadResponse">
+      <sc:onentry>
+        <plc4x:S7DecodeReadResponse timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2"
+                                    idExpression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/tpduReference/text()">
+          <!--verification value="255" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/payloads/payload/s7:S7ResponsePayloadReadVar/item[1]/returnCode/text()"/>
+          <extraction name="s7ReadData" xpath-expression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/payloads/payload/s7:S7ResponsePayloadReadVar/item[1]/data/text()"/-->
+        </plc4x:S7DecodeReadResponse>
       </sc:onentry>
+      <sc:transition event="success" target="connected"/>
+      <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
+    </sc:state>
+
+    <sc:state id="sendS7WriteRequest">
+      <sc:datamodel>
+        <sc:data id="requestId"/>
+      </sc:datamodel>
+      <sc:onentry>
+        <plc4x:sendRequest idExpression="/s7:TpktMessage/userData/userData/s7:S7RequestMessage/tpduReference/text()">
+          <s7:TpktMessage>
+            <magicByte>3</magicByte>
+            <reserved>0</reserved>
+            <length>39</length>
+            <userData>
+              <headerLength>2</headerLength>
+              <type>240</type>
+              <s7:CotpTpduData>
+                <endOfTransmission>1</endOfTransmission>
+                <tpduRef>0</tpduRef>
+              </s7:CotpTpduData>
+              <userData>
+                <magicByte>50</magicByte>
+                <type>1</type>
+                <s7:S7RequestMessage>
+                  <reserved>0</reserved>
+                  <tpduReference>${requestId}</tpduReference>
+                  <parametersLength>14</parametersLength>
+                  <payloadsLength>8</payloadsLength>
+                  <parameters>
+                    <parameter>
+                      <type>5</type>
+                      <s7:S7RequestParameterWriteVar>
+                        <numItems>1</numItems>
+                        <items>
+                          <item>
+                            <type>18</type>
+                            <s7:S7RequestParameterWriteVarAnyItem>
+                              <itemLength>10</itemLength>
+                              <addressingMode>16</addressingMode>
+                              <dataType>8</dataType><!--8 ${s7WriteDataType}-->
+                              <numElements>1</numElements><!--1 ${s7WriteNumElements}-->
+                              <dataBlockNumber>0</dataBlockNumber><!--0 ${s7WriteDataBlockNumber}-->
+                              <memoryArea>131</memoryArea><!--131 ${s7WriteMemoryArea}-->
+                              <byteOffset>16</byteOffset><!--16 ${s7WriteByteOffset}-->
+                              <bitOffset>0</bitOffset><!--0 ${s7WriteBitOffset}-->
+                            </s7:S7RequestParameterWriteVarAnyItem>
+                          </item>
+                        </items>
+                      </s7:S7RequestParameterWriteVar>
+                    </parameter>
+                  </parameters>
+                  <payloads>
+                    <payload>
+                      <s7:S7RequestPayloadWriteVar>
+                        <numItems>1</numItems>
+                        <item>
+                          <returnCode>0</returnCode>
+                          <transportSize>7</transportSize><!--7 ${s7WriteTransportSize}-->
+                          <rawLength>4</rawLength><!--4 ${s7WriteLength}-->
+                          <lengthInBytes>4</lengthInBytes><!--4 ${s7WriteLengthInBytes}-->
+                          <data>79E9F642</data><!--79E9F642 ${s7WriteData}-->
+                        </item>
+                      </s7:S7RequestPayloadWriteVar>
+                    </payload>
+                  </payloads>
+                </s7:S7RequestMessage>
+              </userData>
+            </userData>
+          </s7:TpktMessage>
+        </plc4x:sendRequest>
+      </sc:onentry>
+      <sc:transition event="success" target="receiveS7WriteResponse"/>
+      <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
+    </sc:state>
+
+    <sc:state id="receiveS7WriteResponse">
+      <sc:onentry>
+        <plc4x:S7DecodeWriteResponse timeout="5000" packetLengthStartPosition="2" packetLengthSizeInBytes="2"
+                               idExpression="/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/tpduReference/text()">
+          <!--verification value="255" xpath-expression="/s7:tpktMessage/userData/userData/s7:S7ResponseMessage/payloads/payload/s7:S7ResponsePayloadReadVar/item[1]/returnCode/text()"/-->
+        </plc4x:S7DecodeWriteResponse>
+      </sc:onentry>
+      <sc:transition event="success" target="connected"/>
+      <sc:transition event="failure" target="error"/>
       <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
diff --git a/sandbox/dynamic-driver-base/pom.xml b/sandbox/dynamic-driver-base/pom.xml
index 4f8e554..ea25bac 100644
--- a/sandbox/dynamic-driver-base/pom.xml
+++ b/sandbox/dynamic-driver-base/pom.xml
@@ -37,6 +37,11 @@
       <artifactId>plc4j-api</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.commons</groupId>
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
index 3693294..4aff576 100644
--- a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
@@ -39,7 +39,7 @@ public abstract class BasePlc4xAction extends Action {
     }
 
     protected void fireFailureEvent(ActionExecutionContext ctx, String message) {
-        TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
+        TriggerEvent event = new EventBuilder("failure", TriggerEvent.ERROR_EVENT).
             data(getStateName() + ": " + message).build();
         ctx.getInternalIOProcessor().addEvent(event);
     }
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
index bbc3b5d..c005382 100644
--- a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
@@ -24,6 +24,7 @@ import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.TriggerEvent;
 import org.apache.daffodil.japi.Compiler;
 import org.apache.daffodil.japi.*;
+import org.apache.plc4x.sandbox.java.dynamic.utils.RequestRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,8 +34,17 @@ import java.util.List;
 
 public class InitContextAction extends BasePlc4xAction {
 
+    private long maxRequestId;
     private String protocolDaffodilSchemaName;
 
+    public String getMaxRequestId() {
+        return Long.toString(maxRequestId);
+    }
+
+    public void setMaxRequestId(String maxRequestId) {
+        this.maxRequestId = Long.valueOf(maxRequestId);
+    }
+
     public String getProtocolDaffodilSchemaName() {
         return protocolDaffodilSchemaName;
     }
@@ -52,6 +62,8 @@ public class InitContextAction extends BasePlc4xAction {
     public void execute(ActionExecutionContext ctx) {
         ctx.getAppLog().info(getStateName() + ": Initializing Context...");
 
+        // Initialize the Daffodil system for parsing and serializing the
+        // protocol messages.
         try {
             Compiler c = Daffodil.compiler();
             c.setValidateDFDLSchemas(true);
@@ -72,7 +84,12 @@ public class InitContextAction extends BasePlc4xAction {
             return;
         }
 
+        // Create a new request-registry that will be used for matching
+        // requests and responses.
+        ctx.getGlobalContext().set("requestRegistry", new RequestRegistry(maxRequestId));
+
         ctx.getAppLog().info("Context initialized.");
+
         fireSuccessEvent(ctx);
     }
 
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
index 4db3fd9..8c9a45f 100644
--- a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
@@ -22,9 +22,6 @@ package org.apache.plc4x.sandbox.java.dynamic.actions;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.EventBuilder;
 import org.apache.commons.scxml2.TriggerEvent;
-import org.apache.commons.scxml2.model.NodeListValue;
-import org.apache.commons.scxml2.model.NodeValue;
-import org.apache.commons.scxml2.model.ParsedValue;
 import org.apache.daffodil.japi.DataProcessor;
 import org.apache.daffodil.japi.ParseResult;
 import org.apache.daffodil.japi.infoset.JDOMInfosetOutputter;
@@ -38,34 +35,21 @@ import org.jdom2.xpath.XPathExpression;
 import org.jdom2.xpath.XPathFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
-import java.io.IOException;
 import java.net.Socket;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
-public class ReceiveAction extends BaseDaffodilAction {
+public abstract class ReceiveAction extends BaseDaffodilAction {
 
     private long timeout = 5000;
     private int packetLengthStartPosition;
     private int packetLengthSizeInBytes;
     private int packetLengthOffset = 0;
 
-    private final Map<String, String> verificationRules;
-    private final Map<String, String> extractionRules;
-
-    public ReceiveAction() {
-        verificationRules = new HashMap<>();
-        extractionRules = new HashMap<>();
-    }
-
     @Override
     protected Logger getLogger() {
         return LoggerFactory.getLogger(ReceiveAction.class);
@@ -104,36 +88,6 @@ public class ReceiveAction extends BaseDaffodilAction {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public void setParsedValue(ParsedValue parsedValue) {
-        super.setParsedValue(parsedValue);
-        if(parsedValue != null) {
-            if(parsedValue instanceof NodeListValue) {
-                List<Node> ruleList = (List<Node>) parsedValue.getValue();
-                for (Node node : ruleList) {
-                    if(node instanceof Element) {
-                        parseElement((Element) node);
-                    }
-                }
-            } else if(parsedValue instanceof NodeValue) {
-                parseElement((Element) parsedValue.getValue());
-            }
-        }
-    }
-
-    private void parseElement(Element ruleElement) {
-        String name = ruleElement.getAttribute("name");
-        String expression = ruleElement.getAttribute("xpath-expression");
-        if ("verification".equals(ruleElement.getTagName())) {
-            verificationRules.put(name, expression);
-        } else if ("extraction".equals(ruleElement.getTagName())) {
-            extractionRules.put(name, expression);
-        } else {
-            getLogger().error("unsupported rule type: " + ruleElement.getTagName());
-        }
-    }
-
-    @Override
     public void execute(ActionExecutionContext ctx) {
         ctx.getAppLog().info(getStateName() + ": Receiving...");
 
@@ -178,7 +132,7 @@ public class ReceiveAction extends BaseDaffodilAction {
             // Go back to the beginning of the packet.
             inputStream.reset();
 
-            // Eventually wait till the entire packet is available.
+            // Wait till the entire packet is available.
             while(inputStream.available() < packetLength) {
                 waitWithTimeout(ctx, startTime, timeout);
             }
@@ -203,38 +157,19 @@ public class ReceiveAction extends BaseDaffodilAction {
             // Get the resulting XML document from the parser.
             Document message = outputter.getResult();
 
-            // First verify all verification conditions.
-            for (Map.Entry<String, String> rule : verificationRules.entrySet()) {
-                Object reference = ctx.getGlobalContext().get(rule.getKey());
-                String current = getRuleText(message, rule.getValue());
-                if(current == null) {
-                    fireFailureEvent(ctx, "Error verifying. Expected: " + reference.toString() + " got null value");
-                    return;
-                }
-                if(!current.equals(reference)) {
-                    fireFailureEvent(ctx, "Error verifying. Expected: " + reference.toString() + " got: " + current);
-                    return;
-                }
-            }
-
-            // Then extract data from the document.
-            for (Map.Entry<String, String> rule : extractionRules.entrySet()) {
-                String current = getRuleText(message, rule.getValue());
-                if(current == null) {
-                    fireFailureEvent(ctx, "Error extracting. Got null value");
-                    return;
-                }
-                ctx.getGlobalContext().set(rule.getKey(), current);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
+            // Do any form of processing.
+            processMessage(message, ctx);
+        } catch (Exception e) {
+            fireFailureEvent(ctx, e.getMessage());
         }
 
         ctx.getAppLog().info("Received.");
         fireSuccessEvent(ctx);
     }
 
-    private String getRuleText(Document message, String xpathExpression) {
+    protected abstract void processMessage(Document message, ActionExecutionContext ctx);
+
+    String getRuleText(Document message, String xpathExpression) {
         // Get the namespace definitions from the input document.
         List<Namespace> namespaces = message.getRootElement().getNamespacesInScope();
 
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveExtractVerifyAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveExtractVerifyAction.java
new file mode 100644
index 0000000..08c27d8
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveExtractVerifyAction.java
@@ -0,0 +1,114 @@
+/*
+ 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.sandbox.java.dynamic.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.commons.scxml2.model.NodeListValue;
+import org.apache.commons.scxml2.model.NodeValue;
+import org.apache.commons.scxml2.model.ParsedValue;
+import org.jdom2.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ReceiveExtractVerifyAction extends ReceiveAction {
+
+    private final Map<String, String> valueVerificationRules;
+    private final Map<String, String> contextVerificationRules;
+    private final Map<String, String> extractionRules;
+
+    public ReceiveExtractVerifyAction() {
+        valueVerificationRules = new HashMap<>();
+        contextVerificationRules = new HashMap<>();
+        extractionRules = new HashMap<>();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void setParsedValue(ParsedValue parsedValue) {
+        super.setParsedValue(parsedValue);
+        if(parsedValue != null) {
+            if(parsedValue instanceof NodeListValue) {
+                List<Node> ruleList = (List<Node>) parsedValue.getValue();
+                for (Node node : ruleList) {
+                    if(node instanceof Element) {
+                        parseElement((Element) node);
+                    }
+                }
+            } else if(parsedValue instanceof NodeValue) {
+                parseElement((Element) parsedValue.getValue());
+            }
+        }
+    }
+
+    private void parseElement(Element ruleElement) {
+        String expression = ruleElement.getAttribute("xpath-expression");
+        if ("verification".equals(ruleElement.getTagName())) {
+            if(ruleElement.hasAttribute("name")) {
+                String name = ruleElement.getAttribute("name");
+                contextVerificationRules.put(expression, name);
+            } else if(ruleElement.hasAttribute("value")) {
+                String value = ruleElement.getAttribute("value");
+                valueVerificationRules.put(expression, value);
+            }
+        } else if ("extraction".equals(ruleElement.getTagName())) {
+            String name = ruleElement.getAttribute("name");
+            extractionRules.put(expression, name);
+        } else {
+            getLogger().error("unsupported rule type: " + ruleElement.getTagName());
+        }
+    }
+
+
+    protected void processMessage(Document message, ActionExecutionContext ctx) {
+        // First verify all verification conditions.
+        for (Map.Entry<String, String> rule : contextVerificationRules.entrySet()) {
+            Object reference = ctx.getGlobalContext().get(rule.getValue());
+            verifyValue(message, rule.getKey(), reference);
+        }
+        for (Map.Entry<String, String> rule : valueVerificationRules.entrySet()) {
+            Object reference = rule.getValue();
+            verifyValue(message, rule.getKey(), reference);
+        }
+
+        // Then extract data from the document.
+        for (Map.Entry<String, String> rule : extractionRules.entrySet()) {
+            String current = getRuleText(message, rule.getKey());
+            if(current == null) {
+                throw new RuntimeException("Error extracting. Got null value");
+            }
+            ctx.getGlobalContext().set(rule.getValue(), current);
+        }
+    }
+
+    private void verifyValue(Document message, String xpath, Object reference) {
+        String current = getRuleText(message, xpath);
+        if(current == null) {
+            throw new RuntimeException("Error verifying. Expected: " + reference.toString() + " got null value");
+        }
+        if(!current.equals(reference)) {
+            throw new RuntimeException("Error verifying. Expected: " + reference.toString() + " got: " + current);
+        }
+    }
+
+}
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveRequestAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveRequestAction.java
new file mode 100644
index 0000000..19187ab
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveRequestAction.java
@@ -0,0 +1,52 @@
+/*
+ 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.sandbox.java.dynamic.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.jdom2.Document;
+
+public class ReceiveRequestAction extends ReceiveAction {
+
+    private String idExpression = null;
+
+    public String getIdExpression() {
+        return idExpression;
+    }
+
+    public void setIdExpression(String idExpression) {
+        this.idExpression = idExpression;
+    }
+
+    @Override
+    public void execute(ActionExecutionContext ctx) {
+        if (idExpression == null) {
+            fireFailureEvent(ctx, "'id' element not present");
+            return;
+        }
+        super.execute(ctx);
+    }
+
+    @Override
+    protected void processMessage(Document message, ActionExecutionContext ctx) {
+        String requestId = getRuleText(message, idExpression);
+
+    }
+
+}
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveResponseAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveResponseAction.java
new file mode 100644
index 0000000..69855df
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveResponseAction.java
@@ -0,0 +1,65 @@
+/*
+ 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.sandbox.java.dynamic.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.sandbox.java.dynamic.utils.RequestRegistry;
+import org.jdom2.Document;
+
+public abstract class ReceiveResponseAction extends ReceiveAction {
+
+    private String idExpression = null;
+
+    public String getIdExpression() {
+        return idExpression;
+    }
+
+    public void setIdExpression(String idExpression) {
+        this.idExpression = idExpression;
+    }
+
+    @Override
+    public void execute(ActionExecutionContext ctx) {
+        if(idExpression == null) {
+            fireFailureEvent(ctx, "'id' element not present");
+            return;
+        }
+        super.execute(ctx);
+    }
+
+    @Override
+    protected void processMessage(Document message, ActionExecutionContext ctx) {
+        // Get the responseId (which usually should match the corresponding request id.
+        String requestId = getRuleText(message, idExpression);
+
+        // Get access to any pre-registered containers.
+        RequestRegistry requestRegistry = (RequestRegistry) ctx.getGlobalContext().get("requestRegistry");
+        PlcRequestContainer container = requestRegistry.removeContainer(requestId);
+
+        // If a container was found, do the processing of the response.
+        if(container != null) {
+            processResponse(message, ctx, container);
+        }
+    }
+
+    protected abstract void processResponse(Document message, ActionExecutionContext ctx, PlcRequestContainer container);
+
+}
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
index 6421cf6..914700c 100644
--- a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
@@ -24,15 +24,13 @@ import org.apache.commons.scxml2.model.ParsedValue;
 import org.apache.daffodil.japi.DataProcessor;
 import org.apache.daffodil.japi.UnparseResult;
 import org.apache.daffodil.japi.infoset.InfosetInputter;
-import org.apache.plc4x.sandbox.java.dynamic.utils.W3CDOMTemplateInfosetInputter;
+import org.apache.plc4x.sandbox.java.dynamic.utils.JDOMTemplateInfosetInputter;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.input.DOMBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.net.Socket;
@@ -41,31 +39,39 @@ import java.nio.channels.WritableByteChannel;
 
 public class SendAction extends BaseDaffodilAction {
 
+    private Document messageTemplate;
+
     @Override
     protected Logger getLogger() {
         return LoggerFactory.getLogger(SendAction.class);
     }
 
     @Override
+    public void setParsedValue(ParsedValue parsedValue) {
+        super.setParsedValue(parsedValue);
+
+        // Convert the W3C Dom implementation into JDom2.
+        Element element = new DOMBuilder().build(
+            (org.w3c.dom.Element) getParsedValue().getValue());
+        messageTemplate = element.getDocument();
+    }
+
+    @Override
     public void execute(ActionExecutionContext ctx) {
         ctx.getAppLog().info(getStateName() + ": Sending...");
 
         if(getParsedValue() != null) {
             if(getParsedValue().getType() == ParsedValue.ValueType.NODE) {
                 try {
-                    Node messageTemplate = (Node) getParsedValue().getValue();
-                    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-                    DocumentBuilder builder = dbf.newDocumentBuilder();
-                    Document doc = builder.newDocument();
-                    Node messageTemplateClone = doc.importNode(messageTemplate, true);
-                    doc.appendChild(messageTemplateClone);
+                    // Do any form of processing.
+                    processMessage(messageTemplate, ctx);
 
                     DataProcessor dp = getDaffodilDataProcessor(ctx);
                     if(dp == null) {
                         fireFailureEvent(ctx, "Couldn't initialize daffodil data processor.");
                         return;
                     }
-                    InfosetInputter inputter = new W3CDOMTemplateInfosetInputter(doc, ctx.getGlobalContext());
+                    InfosetInputter inputter = new JDOMTemplateInfosetInputter(messageTemplate, ctx.getGlobalContext());
 
                     Socket connection = getSocket(ctx);
                     DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
@@ -76,7 +82,7 @@ public class SendAction extends BaseDaffodilAction {
                         return;
                     }
                     outputStream.flush();
-                } catch(IOException | ParserConfigurationException e) {
+                } catch(IOException e) {
                     e.printStackTrace();
                 }
             } else {
@@ -89,4 +95,7 @@ public class SendAction extends BaseDaffodilAction {
         fireSuccessEvent(ctx);
     }
 
+    protected void processMessage(Document message, ActionExecutionContext ctx) {
+    }
+
 }
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendRequestAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendRequestAction.java
new file mode 100644
index 0000000..92f0f17
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendRequestAction.java
@@ -0,0 +1,57 @@
+/*
+ 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.sandbox.java.dynamic.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.sandbox.java.dynamic.utils.RequestRegistry;
+import org.jdom2.Document;
+
+public class SendRequestAction extends SendAction {
+
+    private String idExpression = null;
+
+    public String getIdExpression() {
+        return idExpression;
+    }
+
+    public void setIdExpression(String idExpression) {
+        this.idExpression = idExpression;
+    }
+
+    @Override
+    protected void processMessage(Document message, ActionExecutionContext ctx) {
+        // Generate a new request and add that to the context.
+        RequestRegistry requestRegistry = (RequestRegistry) ctx.getGlobalContext().get("requestRegistry");
+        String requestId = requestRegistry.generateRequestId();
+        ctx.getGlobalContext().set("requestId", requestId);
+
+        // If a container is present, we want to respond to a call from outside the driver.
+        // Register the container with the registry using the requestId as key.
+        PlcRequestContainer container = (PlcRequestContainer) ctx.getGlobalContext().get("container");
+        if(container != null) {
+            requestRegistry.addContainer(requestId, container);
+        }
+
+        // Do the normal processing.
+        super.processMessage(message, ctx);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java
index d27510d..bb1ea8f 100644
--- a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java
@@ -32,16 +32,14 @@ import org.apache.commons.scxml2.model.SCXML;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.metadata.PlcConnectionMetadata;
-import org.apache.plc4x.sandbox.java.dynamic.actions.ConnectAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.InitContextAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.ReceiveAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.SendAction;
+import org.apache.plc4x.java.base.connection.AbstractPlcConnection;
+import org.apache.plc4x.sandbox.java.dynamic.actions.*;
 
 import javax.xml.stream.XMLStreamException;
 import java.io.IOException;
 import java.util.*;
 
-public abstract class DynamicDriverConnectionBase implements PlcConnection {
+public abstract class DynamicDriverConnectionBase extends AbstractPlcConnection implements PlcConnection {
 
     private String stateMachineURI;
     private String dataFormatURI;
@@ -62,7 +60,9 @@ public abstract class DynamicDriverConnectionBase implements PlcConnection {
         customActions.add(
             new CustomAction("https://plc4x.apache.org/scxml-extension", "send", SendAction.class));
         customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "receive", ReceiveAction.class));
+            new CustomAction("https://plc4x.apache.org/scxml-extension", "receiveExtractVerify", ReceiveExtractVerifyAction.class));
+        customActions.add(
+            new CustomAction("https://plc4x.apache.org/scxml-extension", "sendRequest", SendRequestAction.class));
         customActions.addAll(getAdditionalCustomActions());
 
         try {
@@ -80,6 +80,10 @@ public abstract class DynamicDriverConnectionBase implements PlcConnection {
         }
     }
 
+    protected SCXMLExecutor getExecutor() {
+        return executor;
+    }
+
     protected Collection<CustomAction> getAdditionalCustomActions() {
         return Collections.emptyList();
     }
@@ -123,12 +127,27 @@ public abstract class DynamicDriverConnectionBase implements PlcConnection {
         if(executor == null) {
             return;
         }
-        executor.triggerEvent(new EventBuilder(getDisconnectTransitionName(), TriggerEvent.SIGNAL_EVENT).build());
+        executor.triggerEvent(new EventBuilder(getDisconnectTransitionName(), TriggerEvent.CALL_EVENT).build());
     }
 
     @Override
     public PlcConnectionMetadata getMetadata() {
-        return null;
+        return new PlcConnectionMetadata() {
+            @Override
+            public boolean canRead() {
+                return true;
+            }
+
+            @Override
+            public boolean canWrite() {
+                return false;
+            }
+
+            @Override
+            public boolean canSubscribe() {
+                return false;
+            }
+        };
     }
 
 }
diff --git a/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/utils/RequestRegistry.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/utils/RequestRegistry.java
new file mode 100644
index 0000000..9176b94
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/utils/RequestRegistry.java
@@ -0,0 +1,66 @@
+/*
+ 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.sandbox.java.dynamic.utils;
+
+import org.apache.commons.scxml2.env.AbstractSCXMLListener;
+import org.apache.commons.scxml2.model.EnterableState;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class RequestRegistry extends AbstractSCXMLListener {
+
+    private final long maxValue;
+    private AtomicLong idGenerator = new AtomicLong(0);
+
+    // TODO: Add some timeout stuff here ...
+    private ConcurrentHashMap<String, PlcRequestContainer> requestContainers;
+
+    public RequestRegistry(long maxValue) {
+        this.maxValue = maxValue;
+        requestContainers = new ConcurrentHashMap<>();
+    }
+
+    public String generateRequestId() {
+        // If we reached the max value, reset to 0.
+        if(idGenerator.get() == maxValue) {
+            idGenerator.set(0);
+        }
+        return Long.toString(idGenerator.getAndIncrement());
+    }
+
+    public void addContainer(String requestId, PlcRequestContainer container) {
+        requestContainers.put(requestId, container);
+    }
+
+    public PlcRequestContainer removeContainer(String requestId) {
+        if(requestId != null) {
+            return requestContainers.remove(requestId);
+        }
+        return null;
+    }
+
+    @Override
+    public void onExit(EnterableState state) {
+        super.onExit(state);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala b/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/JDOMTemplateInfosetInputter.scala
similarity index 70%
rename from sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
rename to sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/JDOMTemplateInfosetInputter.scala
index d2c517f..1a1cb3f 100644
--- a/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
+++ b/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/JDOMTemplateInfosetInputter.scala
@@ -20,21 +20,24 @@
 package org.apache.plc4x.sandbox.java.dynamic.utils
 
 import org.apache.commons.scxml2.Context
+import org.apache.commons.scxml2.env.jexl.JexlEvaluator
 import org.apache.daffodil.dpath.NodeInfo
-import org.apache.daffodil.japi.infoset.{InfosetInputterProxy, W3CDOMInfosetInputter}
+import org.apache.daffodil.infoset.JDOMInfosetInputter
+import org.apache.daffodil.japi.infoset.InfosetInputterProxy
+import org.jdom2.Document
 
-class W3CDOMTemplateInfosetInputter(document: org.w3c.dom.Document, context: Context) extends InfosetInputterProxy {
+class JDOMTemplateInfosetInputter(document: Document, context: Context) extends InfosetInputterProxy {
 
-    override val infosetInputter = new W3CDOMInfosetInputter(document)
+    override val infosetInputter = new JDOMInfosetInputter(document)
+
+    val evaluator = new JexlEvaluator()
 
     override def getSimpleText(primType: NodeInfo.Kind): String = {
         val value = super.getSimpleText(primType)
         if(value.startsWith("${") && value.endsWith("}")) {
             val varName = value.substring(2, value.length - 1)
-            val varValue = context.get(varName)
-            if(varValue.isInstanceOf[String]) {
-                return varValue.toString
-            }
+            val varValue = evaluator.eval(context, varName)
+            return varValue.toString
         }
         value
     }
diff --git a/sandbox/dynamic-driver-s7/pom.xml b/sandbox/dynamic-driver-s7/pom.xml
index 4f592ec..80344fc 100644
--- a/sandbox/dynamic-driver-s7/pom.xml
+++ b/sandbox/dynamic-driver-s7/pom.xml
@@ -37,7 +37,11 @@
       <artifactId>plc4j-api</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.plc4x.sandbox</groupId>
       <artifactId>plc4j-dynamic-driver-base</artifactId>
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java
index a5b1eb5..3b1cadc 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java
@@ -59,9 +59,7 @@ public class DynamicS7Driver implements PlcDriver {
 
         try {
             InetAddress serverInetAddress = InetAddress.getByName(host);
-            DynamicS7Connection connection = new DynamicS7Connection(serverInetAddress, rack, slot, params);
-            connection.connect();
-            return connection;
+            return new DynamicS7Connection(serverInetAddress, rack, slot, params);
         } catch (UnknownHostException e) {
             throw new PlcConnectionException("Error parsing address", e);
         } catch (Exception e) {
@@ -74,4 +72,9 @@ public class DynamicS7Driver implements PlcDriver {
         throw new PlcConnectionException("Basic S7 connections don't support authentication.");
     }
 
+    public static void main(String[] args) throws Exception {
+        PlcConnection connection = new DynamicS7Driver().connect("s7://10.10.64.20/1/1");
+        connection.isConnected();
+    }
+
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java
deleted file mode 100644
index fe3d771..0000000
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java
+++ /dev/null
@@ -1,102 +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.sandbox.java.dynamic.s7;
-
-import org.apache.commons.scxml2.SCXMLExecutor;
-import org.apache.commons.scxml2.env.SimpleDispatcher;
-import org.apache.commons.scxml2.env.SimpleErrorReporter;
-import org.apache.commons.scxml2.invoke.SimpleSCXMLInvoker;
-import org.apache.commons.scxml2.io.SCXMLReader;
-import org.apache.commons.scxml2.model.CustomAction;
-import org.apache.commons.scxml2.model.SCXML;
-import org.apache.plc4x.java.api.PlcConnection;
-import org.apache.plc4x.sandbox.java.dynamic.actions.ConnectAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.InitContextAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.ReceiveAction;
-import org.apache.plc4x.sandbox.java.dynamic.actions.SendAction;
-import org.apache.plc4x.sandbox.java.dynamic.s7.actions.S7DecodeArticleNumber;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public class Poc {
-
-    private String dataFormatURI;
-
-    private SCXMLExecutor executor;
-
-    private Poc(String stateMachineURI, String dataFormatURI) throws Exception {
-        this.dataFormatURI = dataFormatURI;
-
-        // Initialize our PLC4X specific actions.
-        List<CustomAction> customActions = new LinkedList<>();
-        customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "initContext", InitContextAction.class));
-        customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "connect", ConnectAction.class));
-        customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "send", SendAction.class));
-        customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "receive", ReceiveAction.class));
-        customActions.add(
-            new CustomAction("https://plc4x.apache.org/scxml-extension", "S7DecodeArticleNumber", S7DecodeArticleNumber.class));
-
-        // Initialize the state-machine with the definition from the protocol module.
-        SCXML scxml = SCXMLReader.read(
-            Poc.class.getClassLoader().getResource(stateMachineURI),
-            new SCXMLReader.Configuration(null, null, customActions));
-
-        // Create an executor for running the state-machine.
-        executor = new SCXMLExecutor(null, new SimpleDispatcher(), new SimpleErrorReporter());
-        executor.setStateMachine(scxml);
-        executor.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
-    }
-
-    private void run() throws Exception {
-        Map<String, Object> context = new HashMap<>();
-        context.put("protocolDaffodilSchema", dataFormatURI);
-
-        context.put("cotpLocalReference", "15");
-        context.put("cotpCalledTsap", "512");
-        context.put("cotpCallingTsap", "273");
-        context.put("cotpTpduSize", "10");
-        context.put("s7MaxAmqCaller", "10");
-        context.put("s7MaxAmqCallee", "10");
-        context.put("s7PduLength", "1024");
-
-        //context.put("plcType", "HURZ");
-
-        // Run the state-machine.
-        executor.go(context);
-    }
-
-    public static void main(String[] args) throws Exception {
-        /*Poc poc = new Poc(
-            "org/apache/plc4x/protocols/s7/protocol.scxml.xml",
-            "org/apache/plc4x/protocols/s7/protocol.dfdl.xsd");
-        poc.run();*/
-
-        PlcConnection connection = new DynamicS7Driver().connect("s7://10.10.64.20/1/1");
-        connection.isConnected();
-    }
-
-}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeReadResponseAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeReadResponseAction.java
new file mode 100644
index 0000000..1b21485
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeReadResponseAction.java
@@ -0,0 +1,315 @@
+/*
+ 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.sandbox.java.dynamic.s7.actions;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.base.messages.DefaultPlcReadResponse;
+import org.apache.plc4x.java.base.messages.InternalPlcReadRequest;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.items.*;
+import org.apache.plc4x.sandbox.java.dynamic.actions.ReceiveResponseAction;
+import org.apache.plc4x.sandbox.java.dynamic.s7.types.DataTransportErrorCode;
+import org.apache.plc4x.sandbox.java.dynamic.s7.utils.S7Field;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.Namespace;
+import org.jdom2.filter.Filters;
+import org.jdom2.xpath.XPathExpression;
+import org.jdom2.xpath.XPathFactory;
+
+import javax.xml.bind.DatatypeConverter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+public class S7DecodeReadResponseAction extends ReceiveResponseAction {
+
+    @Override
+    protected void processResponse(Document message, ActionExecutionContext ctx, PlcRequestContainer container) {
+        InternalPlcReadRequest readRequest = (InternalPlcReadRequest) container.getRequest();
+        LinkedHashSet<String> fieldNames = readRequest.getFieldNames();
+
+        List<Namespace> namespaces = message.getRootElement().getNamespacesInScope();
+        XPathFactory xPathFactory = XPathFactory.instance();
+        XPathExpression<Element> xpath = xPathFactory.compile(
+            "/s7:TpktMessage/userData/userData/s7:S7ResponseMessage/payloads/payload/s7:S7ResponsePayloadReadVar/item", Filters.element(), null, namespaces);
+        List<Element> items = xpath.evaluate(message);
+
+        // If the sizes don't match, something is wrong.
+        if(items.size() != fieldNames.size()) {
+            container.getResponseFuture().completeExceptionally(
+                new PlcProtocolException("Response item size doesn't match request item size."));
+            return;
+        }
+
+        Map<String, Pair<PlcResponseCode, BaseDefaultFieldItem>> responseItems = new HashMap<>(items.size());
+        int i = 0;
+        for (String fieldName : fieldNames) {
+            S7Field field = (S7Field) readRequest.getField(fieldName);
+
+            Element item = items.get(i);
+            String returnCode = item.getChild("returnCode").getTextTrim();
+            byte returnCodeValue = (byte) (Short.valueOf(returnCode) & 0xFF);
+            PlcResponseCode responseCode = null;
+            BaseDefaultFieldItem fieldItem = null;
+            switch(DataTransportErrorCode.valueOf(returnCodeValue)) {
+                case RESERVED:
+                    responseCode = PlcResponseCode.INTERNAL_ERROR;
+                    break;
+                case ACCESS_DENIED:
+                    responseCode = PlcResponseCode.ACCESS_DENIED;
+                    break;
+                case DATA_TYPE_NOT_SUPPORTED:
+                    responseCode = PlcResponseCode.INVALID_DATATYPE;
+                    break;
+                case INVALID_ADDRESS:
+                    responseCode = PlcResponseCode.INVALID_ADDRESS;
+                    break;
+                case NOT_FOUND:
+                    responseCode = PlcResponseCode.NOT_FOUND;
+                    break;
+                case OK: {
+                    responseCode = PlcResponseCode.OK;
+                    // Convert the hex encoded payload into a real byte array.
+                    byte[] data = DatatypeConverter.parseHexBinary(item.getChild("data").getTextTrim());
+
+                    // Depending on the field type in the request, interpret the data in the response accordingly.
+                    switch (field.getDataType()) {
+                        case BOOL: {
+                            BitSet bits = BitSet.valueOf(data);
+                            Boolean[] values = new Boolean[field.getNumElements()];
+                            for (int bitNr = 0; bitNr < field.getNumElements(); bitNr++) {
+                                values[bitNr] = bits.get(bitNr);
+                            }
+                            fieldItem = new DefaultBooleanFieldItem(values);
+                            break;
+                        }
+                        // -----------------------------------------
+                        // Bit strings
+                        // In Tia and Step7 these types are marked as bit-strings
+                        // which is a sequence of bits. Therefore the result will
+                        // have more items than the request requested.
+                        // -----------------------------------------
+                        case BYTE: {
+                            BitSet bits = BitSet.valueOf(data);
+                            Boolean[] values = new Boolean[field.getNumElements() * 8];
+                            for (int bitNr = 0; bitNr < field.getNumElements() * 8; bitNr++) {
+                                values[bitNr] = bits.get(bitNr);
+                            }
+                            fieldItem = new DefaultBooleanFieldItem(values);
+                            break;
+                        }
+                        case WORD: {
+                            BitSet bits = BitSet.valueOf(data);
+                            Boolean[] values = new Boolean[field.getNumElements() * 16];
+                            for (int bitNr = 0; bitNr < field.getNumElements() * 16; bitNr++) {
+                                values[bitNr] = bits.get(bitNr);
+                            }
+                            fieldItem = new DefaultBooleanFieldItem(values);
+                            break;
+                        }
+                        case DWORD: {
+                            BitSet bits = BitSet.valueOf(data);
+                            Boolean[] values = new Boolean[field.getNumElements() * 32];
+                            for (int bitNr = 0; bitNr < field.getNumElements() * 32; bitNr++) {
+                                values[bitNr] = bits.get(bitNr);
+                            }
+                            fieldItem = new DefaultBooleanFieldItem(values);
+                            break;
+                        }
+                        case LWORD: {
+                            BitSet bits = BitSet.valueOf(data);
+                            Boolean[] values = new Boolean[field.getNumElements() * 64];
+                            for (int bitNr = 0; bitNr < field.getNumElements() * 64; bitNr++) {
+                                values[bitNr] = bits.get(bitNr);
+                            }
+                            fieldItem = new DefaultBooleanFieldItem(values);
+                            break;
+                        }
+
+                        // -----------------------------------------
+                        // Integers
+                        // -----------------------------------------
+                        // (Signed) Small Int (8 bit)
+                        case SINT: {
+                            Byte[] values = new Byte[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = data[valueNr];
+                            }
+                            fieldItem = new DefaultByteFieldItem(values);
+                            break;
+                        }
+                        // Unsigned Small Int (8 bit)
+                        case USINT: {
+                            Short[] values = new Short[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = (short) (data[valueNr] & 0xff);
+                            }
+                            fieldItem = new DefaultShortFieldItem(values);
+                            break;
+                        }
+                        // Signed Int (16 bit)
+                        case INT: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Short[] values = new Short[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = buffer.getShort();
+                            }
+                            fieldItem = new DefaultShortFieldItem(values);
+                            break;
+                        }
+                        // Unsigned Int (16 bit)
+                        case UINT: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Integer[] values = new Integer[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = (buffer.getShort() & 0xFFFF);
+                            }
+                            fieldItem = new DefaultIntegerFieldItem(values);
+                            break;
+                        }
+                        // Double Precision Int (32 bit)
+                        case DINT: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Integer[] values = new Integer[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = buffer.getInt();
+                            }
+                            fieldItem = new DefaultIntegerFieldItem(values);
+                            break;
+                        }
+                        // Unsigned Double Precision Int (32 bit)
+                        case UDINT: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Long[] values = new Long[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = (buffer.getInt() & 0xFFFFFFFFL);
+                            }
+                            fieldItem = new DefaultLongFieldItem(values);
+                            break;
+                        }
+                        // Quadrupal Precision Int (64 bit)
+                        case LINT: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Long[] values = new Long[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = buffer.getLong();
+                            }
+                            fieldItem = new DefaultLongFieldItem(values);
+                            break;
+                        }
+                        // Unsigned Quadrupal Precision Int (64 bit)
+                        case ULINT: {
+                            BigInteger[] values = new BigInteger[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                byte[] biBytes = new byte[]{data[valueNr * 8], data[(valueNr * 8) + 1],
+                                    data[(valueNr * 8) + 2], data[(valueNr * 8) + 3], data[(valueNr * 8) + 4],
+                                    data[(valueNr * 8) + 5], data[(valueNr * 8) + 6], data[(valueNr * 8) + 7]};
+                                values[valueNr] = new BigInteger(biBytes);
+                            }
+                            fieldItem = new DefaultBigIntegerFieldItem(values);
+                            break;
+                        }
+
+                        // -----------------------------------------
+                        // Reals
+                        // -----------------------------------------
+                        // (32 bit)
+                        case REAL: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Float[] values = new Float[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = buffer.getFloat();
+                            }
+                            fieldItem = new DefaultFloatFieldItem(values);
+                            break;
+                        }
+                        // (64 bit)
+                        case LREAL: {
+                            ByteBuffer buffer = ByteBuffer.wrap(data);
+                            Double[] values = new Double[field.getNumElements()];
+                            for (int valueNr = 0; valueNr < field.getNumElements(); valueNr++) {
+                                values[valueNr] = buffer.getDouble();
+                            }
+                            fieldItem = new DefaultDoubleFieldItem(values);
+                            break;
+                        }
+
+                        // -----------------------------------------
+                        // Durations
+                        // -----------------------------------------
+                        // IEC time
+                        case TIME:
+                            break;
+                        case LTIME:
+                            break;
+
+                        // -----------------------------------------
+                        // Date
+                        // -----------------------------------------
+                        // IEC date (yyyy-m-d)
+                        case DATE:
+                            break;
+
+                        // -----------------------------------------
+                        // Time of day
+                        // -----------------------------------------
+                        // Time (hh:mm:ss.S)
+                        case TIME_OF_DAY:
+                            break;
+
+                        // -----------------------------------------
+                        // Date and time of day
+                        // -----------------------------------------
+                        case DATE_AND_TIME:
+                            break;
+
+                        // -----------------------------------------
+                        // ASCII Strings
+                        // -----------------------------------------
+                        // Single-byte character
+                        case CHAR:
+                            break;
+                        // Double-byte character
+                        case WCHAR:
+                            break;
+                        // Variable-length single-byte character string
+                        case STRING:
+                            break;
+                        // Variable-length double-byte character string
+                        case WSTRING:
+                            break;
+                    }
+                }
+            }
+            responseItems.put(fieldName, new ImmutablePair<>(responseCode, fieldItem));
+            i++;
+        }
+
+        PlcReadResponse response = new DefaultPlcReadResponse(readRequest, responseItems);
+        container.getResponseFuture().complete(response);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeWriteResponseAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeWriteResponseAction.java
new file mode 100644
index 0000000..868984b
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeWriteResponseAction.java
@@ -0,0 +1,34 @@
+/*
+ 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.sandbox.java.dynamic.s7.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.sandbox.java.dynamic.actions.ReceiveResponseAction;
+import org.jdom2.Document;
+
+public class S7DecodeWriteResponseAction extends ReceiveResponseAction {
+
+    @Override
+    protected void processResponse(Document message, ActionExecutionContext ctx, PlcRequestContainer container) {
+
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java
index a70564a..2138358 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java
@@ -20,25 +20,32 @@
 package org.apache.plc4x.sandbox.java.dynamic.s7.connection;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.scxml2.EventBuilder;
+import org.apache.commons.scxml2.TriggerEvent;
 import org.apache.commons.scxml2.model.CustomAction;
-import org.apache.plc4x.java.api.exceptions.PlcUnsupportedOperationException;
+import org.apache.commons.scxml2.model.ModelException;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
-import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.metadata.PlcConnectionMetadata;
+import org.apache.plc4x.java.base.messages.*;
 import org.apache.plc4x.sandbox.java.dynamic.connection.DynamicDriverConnectionBase;
 import org.apache.plc4x.sandbox.java.dynamic.s7.actions.S7DecodeArticleNumber;
+import org.apache.plc4x.sandbox.java.dynamic.s7.actions.S7DecodeReadResponseAction;
+import org.apache.plc4x.sandbox.java.dynamic.s7.actions.S7DecodeWriteResponseAction;
+import org.apache.plc4x.sandbox.java.dynamic.s7.utils.S7PlcFieldHandler;
 import org.apache.plc4x.sandbox.java.dynamic.s7.utils.S7TsapIdEncoder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.InetAddress;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
 
-public class DynamicS7Connection extends DynamicDriverConnectionBase {
+public class DynamicS7Connection extends DynamicDriverConnectionBase implements PlcReader {
 
     private static final Logger logger = LoggerFactory.getLogger(DynamicS7Connection.class);
 
@@ -119,9 +126,14 @@ public class DynamicS7Connection extends DynamicDriverConnectionBase {
 
     @Override
     protected Collection<CustomAction> getAdditionalCustomActions() {
-        return Collections.singleton(
+        return Arrays.asList(
             new CustomAction("https://plc4x.apache.org/scxml-extension", "S7DecodeArticleNumber",
-                S7DecodeArticleNumber.class));
+                S7DecodeArticleNumber.class),
+            new CustomAction("https://plc4x.apache.org/scxml-extension", "S7DecodeReadResponse",
+                S7DecodeReadResponseAction.class),
+            new CustomAction("https://plc4x.apache.org/scxml-extension", "S7DecodeWriteResponse",
+                S7DecodeWriteResponseAction.class)
+            );
     }
 
     @Override
@@ -145,23 +157,30 @@ public class DynamicS7Connection extends DynamicDriverConnectionBase {
     }
 
     @Override
-    public PlcReadRequest.Builder readRequestBuilder() {
-        throw new PlcUnsupportedOperationException("The connection does not support reading");
+    public PlcConnectionMetadata getMetadata() {
+        return super.getMetadata();
     }
 
     @Override
-    public PlcWriteRequest.Builder writeRequestBuilder() {
-        throw new PlcUnsupportedOperationException("The connection does not support writing");
+    public PlcReadRequest.Builder readRequestBuilder() {
+        return new DefaultPlcReadRequest.Builder(this, new S7PlcFieldHandler());
     }
 
     @Override
-    public PlcSubscriptionRequest.Builder subscriptionRequestBuilder() {
-        throw new PlcUnsupportedOperationException("The connection does not support subscription");
-    }
+    public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+        InternalPlcReadRequest internalReadRequest = checkInternal(readRequest, InternalPlcReadRequest.class);
+        CompletableFuture<InternalPlcReadResponse> future = new CompletableFuture<>();
+        PlcRequestContainer<InternalPlcReadRequest, InternalPlcReadResponse> container =
+            new PlcRequestContainer<>(internalReadRequest, future);
+
+        try {
+            getExecutor().triggerEvent(
+                new EventBuilder("read", TriggerEvent.CALL_EVENT).data(container).build());
+        } catch (ModelException e) {
+            throw new PlcRuntimeException("Error reading.", e);
+        }
 
-    @Override
-    public PlcUnsubscriptionRequest.Builder unsubscriptionRequestBuilder() {
-        throw new PlcUnsupportedOperationException("The connection does not support subscription");
+        return future.thenApply(PlcReadResponse.class::cast);
     }
 
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportErrorCode.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportErrorCode.java
new file mode 100644
index 0000000..c9f520c
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportErrorCode.java
@@ -0,0 +1,62 @@
+/*
+ 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.sandbox.java.dynamic.s7.types;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum DataTransportErrorCode {
+    RESERVED((byte) 0x00),
+    OK((byte) 0xFF),
+    ACCESS_DENIED((byte) 0x03),
+    INVALID_ADDRESS((byte) 0x05),
+    DATA_TYPE_NOT_SUPPORTED((byte) 0x06),
+    NOT_FOUND((byte) 0x0A);
+
+    private static final Logger logger = LoggerFactory.getLogger(DataTransportErrorCode.class);
+
+    private static final Map<Byte, DataTransportErrorCode> map;
+    static {
+        map = new HashMap<>();
+        for (DataTransportErrorCode dataTransportErrorCode : DataTransportErrorCode.values()) {
+            map.put(dataTransportErrorCode.code, dataTransportErrorCode);
+        }
+    }
+
+    private byte code;
+
+    DataTransportErrorCode(byte code) {
+        this.code = code;
+    }
+
+    public byte getCode() {
+        return code;
+    }
+
+    public static DataTransportErrorCode valueOf(byte code) {
+        if (!map.containsKey(code)) {
+            logger.error("No DataTransportErrorCode for code {}", code);
+        }
+        return map.get(code);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportSize.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportSize.java
new file mode 100644
index 0000000..90924e0
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/DataTransportSize.java
@@ -0,0 +1,64 @@
+/*
+ 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.sandbox.java.dynamic.s7.types;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * (Values determined by evaluating generated ".pcap" files)
+ */
+public enum DataTransportSize {
+    NULL((byte) 0x00, false),
+    BIT((byte) 0x03, true),
+    BYTE_WORD_DWORD((byte) 0x04, true),
+    INTEGER((byte) 0x05, true),
+    DINTEGER((byte) 0x06, false),
+    REAL((byte) 0x07, false),
+    OCTET_STRING((byte) 0x09, false);
+
+    private static final Map<Byte, DataTransportSize> map;
+    static {
+        map = new HashMap<>();
+        for (DataTransportSize dataTransportSize : DataTransportSize.values()) {
+            map.put(dataTransportSize.code, dataTransportSize);
+        }
+    }
+
+    private final byte code;
+    private final boolean sizeInBits;
+
+    DataTransportSize(byte code, boolean sizeInBits) {
+        this.code = code;
+        this.sizeInBits = sizeInBits;
+    }
+
+    public byte getCode() {
+        return code;
+    }
+
+    public boolean isSizeInBits() {
+        return sizeInBits;
+    }
+
+    public static DataTransportSize valueOf(byte code) {
+        return map.get(code);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/MemoryArea.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/MemoryArea.java
new file mode 100644
index 0000000..ead1018
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/MemoryArea.java
@@ -0,0 +1,83 @@
+/*
+ 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.sandbox.java.dynamic.s7.types;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * (Values determined by evaluating generated ".pcap" files)
+ */
+public enum MemoryArea {
+    COUNTERS("C", (byte) 0x1C), /* Renamed from "S7 Counters" */ // TODO: Double check shortName
+    TIMERS("T", (byte) 0x1D), /* Renamed from "S7 Timers" */ // TODO: Double check shortName
+    DIRECT_PERIPHERAL_ACCESS("D", (byte) 0x80), // TODO: Double check shortName
+    INPUTS("I", (byte) 0x81),
+    OUTPUTS("Q", (byte) 0x82),
+    FLAGS("F", (byte) 0x83), // TODO: Double check shortName
+    DATA_BLOCKS("DB", (byte) 0x84),
+    INSTANCE_DATA_BLOCKS("DBI", (byte) 0x85), // TODO: Double check shortName
+    LOCAL_DATA("LD", (byte) 0x86); // TODO: Double check shortName
+
+    // TODO: I think we should remove these ...
+    /*S7_200_SYSTEM_INFO(null, (byte) 0x03), * Renamed from "System info of 200 family" *
+    S7_200_FLAGS(null, (byte) 0x05), * Renamed from "System flags of 200 family" *
+    S7_200_INPUTS(null, (byte) 0x06), * Renamed from "System inputs of 200 family" *
+    S7_200_OUTPUTS(null, (byte) 0x07), * Renamed from "System outputs of 200 family" *
+    S7_200_IEC_COUNTERS(null, (byte) 0x1E), * Renamed from "IEC counters (200 family)" *
+    S7_200_IEC_TIMERS(null, (byte) 0x1F); * Renamed from "IEC timers (200 family)" */
+
+    private static final Map<Byte, MemoryArea> map;
+    static {
+        map = new HashMap<>();
+        for (MemoryArea memoryArea : MemoryArea.values()) {
+            map.put(memoryArea.code, memoryArea);
+        }
+    }
+
+    private final String shortName;
+    private final byte code;
+
+    MemoryArea(String shortName, byte code) {
+        this.shortName = shortName;
+        this.code = code;
+    }
+
+    public String getShortName() {
+        return shortName;
+    }
+
+    public byte getCode() {
+        return code;
+    }
+
+    public static MemoryArea valueOfShortName(String shortName) {
+        for (MemoryArea value : MemoryArea.values()) {
+            if(value.getShortName().equals(shortName)) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    public static MemoryArea valueOf(byte code) {
+        return map.get(code);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/S7ControllerType.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/S7ControllerType.java
new file mode 100644
index 0000000..5fee6dd
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/S7ControllerType.java
@@ -0,0 +1,30 @@
+/*
+ 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.sandbox.java.dynamic.s7.types;
+
+public enum S7ControllerType {
+
+    ANY,
+    S7_300,
+    S7_400,
+    S7_1200,
+    S7_1500,
+    LOGO
+
+}
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/TransportSize.java
similarity index 97%
copy from plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
copy to sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/TransportSize.java
index 6de428d..3655993 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/types/TransportSize.java
@@ -16,9 +16,7 @@
  specific language governing permissions and limitations
  under the License.
  */
-package org.apache.plc4x.java.s7.netty.model.types;
-
-import org.apache.plc4x.java.s7.types.S7ControllerType;
+package org.apache.plc4x.sandbox.java.dynamic.s7.types;
 
 import java.util.*;
 
@@ -103,12 +101,12 @@ public enum TransportSize {
     // Single-byte character
     CHAR(0x03, "B", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY),
     // Double-byte character
-    // TODO: Find the code (Eventually 0x13)
+    // TODO: Find the code (Maybe 0x13)
     WCHAR(0x13, "X", 2, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500),
     // Variable-length single-byte character string
     STRING(0x03, "X", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY),
     // Variable-length double-byte character string
-    // TODO: Find the code (Eventually 0x13)
+    // TODO: Find the code (Maybe 0x13)
     WSTRING(0x00, "X", 1, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500);
 
     /* TO BE CONTINUED */
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7Field.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7Field.java
new file mode 100644
index 0000000..fde3c74
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7Field.java
@@ -0,0 +1,194 @@
+/*
+ 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.sandbox.java.dynamic.s7.utils;
+
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.sandbox.java.dynamic.s7.types.MemoryArea;
+import org.apache.plc4x.sandbox.java.dynamic.s7.types.TransportSize;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class S7Field implements PlcField {
+
+    //byteOffset theoretically can reach up to 2097151 ... see checkByteOffset() below --> 7digits
+    private static final Pattern ADDRESS_PATTERN =
+        Pattern.compile("^%(?<memoryArea>.)(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\\[(?<numElements>\\d+)])?");
+
+    //blockNumber usually has its max hat around 64000 --> 5digits
+    private static final Pattern DATA_BLOCK_ADDRESS_PATTERN =
+        Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\\[(?<numElements>\\d+)])?");
+
+    private static final String DATA_TYPE = "dataType";
+    private static final String TRANSFER_SIZE_CODE = "transferSizeCode";
+    private static final String BLOCK_NUMBER = "blockNumber";
+    private static final String BYTE_OFFSET = "byteOffset";
+    private static final String BIT_OFFSET = "bitOffset";
+    private static final String NUM_ELEMENTS = "numElements";
+    private static final String MEMORY_AREA = "memoryArea";
+
+    private final TransportSize dataType;
+    private final MemoryArea memoryArea;
+    private final int blockNumber;
+    private final int byteOffset;
+    private final short bitOffset;
+    private final int numElements;
+
+    private S7Field(TransportSize dataType, MemoryArea memoryArea, int blockNumber, int byteOffset, short bitOffset, int numElements) {
+        this.dataType = dataType;
+        this.memoryArea = memoryArea;
+        this.blockNumber = blockNumber;
+        this.byteOffset = byteOffset;
+        this.bitOffset = bitOffset;
+        this.numElements = numElements;
+    }
+
+    public TransportSize getDataType() {
+        return dataType;
+    }
+
+    public MemoryArea getMemoryArea() {
+        return memoryArea;
+    }
+
+    public int getBlockNumber() {
+        return blockNumber;
+    }
+
+    public int getByteOffset() {
+        return byteOffset;
+    }
+
+    public short getBitOffset() {
+        return bitOffset;
+    }
+
+    public int getNumElements() {
+        return numElements;
+    }
+
+    public static boolean matches(String fieldString) {
+        return DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString).matches() ||
+            ADDRESS_PATTERN.matcher(fieldString).matches();
+    }
+
+    public static S7Field of(String fieldString) {
+        Matcher matcher = DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString);
+        if(matcher.matches()) {
+            TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+            String transferSizeCode = matcher.group(TRANSFER_SIZE_CODE);
+
+            int blockNumber = checkDatablockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+
+            int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+
+            short bitOffset = 0;
+            if(matcher.group(BIT_OFFSET) != null) {
+                bitOffset = Short.parseShort(matcher.group(BIT_OFFSET));
+            } else if(dataType == TransportSize.BOOL) {
+                throw new PlcInvalidFieldException("Expected bit offset for BOOL parameters.");
+            }
+            int numElements = 1;
+            if(matcher.group(NUM_ELEMENTS) != null) {
+                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+            }
+            numElements = calcNumberOfElementsForStringTypes(numElements,dataType);
+            if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
+                throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
+                    "' doesn't match specified data type '" + dataType.name() + "'");
+            }
+            return new S7Field(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements);
+        } else {
+            matcher = ADDRESS_PATTERN.matcher(fieldString);
+            if (matcher.matches()) {
+                TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+                MemoryArea memoryArea = MemoryArea.valueOfShortName(matcher.group(MEMORY_AREA));
+                String transferSizeCode = matcher.group(TRANSFER_SIZE_CODE);
+
+                int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+
+                short bitOffset = 0;
+                if(matcher.group(BIT_OFFSET) != null) {
+                    bitOffset = Short.parseShort(matcher.group(BIT_OFFSET));
+                } else if(dataType == TransportSize.BOOL) {
+                    throw new PlcInvalidFieldException("Expected bit offset for BOOL parameters.");
+                }
+                int numElements = 1;
+                if(matcher.group(NUM_ELEMENTS) != null) {
+                    numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+                }
+                numElements = calcNumberOfElementsForStringTypes(numElements,dataType);
+                if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
+                    throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
+                        "' doesn't match specified data type '" + dataType.name() + "'");
+                }
+                return new S7Field(dataType, memoryArea, (short) 0, byteOffset, bitOffset, numElements);
+            }
+        }
+        throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
+    }
+
+    /**
+     * checks if DatablockNumber of S7Field is in valid range
+     * @param blockNumber given DatablockNumber
+     * @return given blockNumber if Ok, throws PlcInvalidFieldException otherwise
+     */
+    private static int checkDatablockNumber(int blockNumber){
+        //ToDo check the value or add reference - limit eventually depending on active S7 --> make a case selection
+        if(blockNumber>64000 || blockNumber<1){
+            throw new PlcInvalidFieldException("Datablock numbers larger than 64000 or smaller than 1 are not supported.");
+        }
+        return blockNumber;
+    }
+
+    /**
+     * checks if ByteOffset from S7Field is in valid range
+     * @param byteOffset given byteOffset
+     * @return given byteOffset if Ok, throws PlcInvalidFieldException otherwise
+     */
+    private static int checkByteOffset(int byteOffset){
+        //ToDo check the value or add reference
+        if(byteOffset>2097151 || byteOffset<0){
+            throw new PlcInvalidFieldException("ByteOffset must be smaller than 2097151 and positive.");
+        }
+        return byteOffset;
+    }
+
+    /**
+     * correct the storage of "array"-like variables like STRING
+     * @param numElements auto-detected numElements (1 if no numElements in brackets has been given, x if a specific number has been given)
+     * @param dataType detected Transport-Size that represents the data-type
+     * @return corrected numElements if nessesary
+     */
+    private static int calcNumberOfElementsForStringTypes(int numElements,TransportSize dataType){
+        //if no String nothing has to be done
+        if(!dataType.equals(TransportSize.STRING)){
+            return numElements;
+        }
+        //on valid String-length add two byte because of S7-representation of Strings
+        if(numElements>1 && numElements<=254){
+            return numElements+2;
+        }
+        //connection String usage with "STRING" only --> numElements=1 --> enter default value
+        return 256;
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7PlcFieldHandler.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7PlcFieldHandler.java
new file mode 100644
index 0000000..d395821
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7PlcFieldHandler.java
@@ -0,0 +1,569 @@
+/*
+ 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.sandbox.java.dynamic.s7.utils;
+
+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.base.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.base.messages.items.*;
+
+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 S7PlcFieldHandler extends DefaultPlcFieldHandler {
+
+    @Override
+    public PlcField createField(String fieldQuery) {
+        if (S7Field.matches(fieldQuery)) {
+            return S7Field.of(fieldQuery);
+        }
+        throw new PlcInvalidFieldException(fieldQuery);
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeBoolean(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        // All of these types are declared as Bit or Bit-String types.
+        switch (s7Field.getDataType()) {
+            case BOOL:
+            case BYTE:
+            case WORD:
+            case DWORD:
+            case LWORD:
+                return internalEncodeBoolean(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeByte(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        // All of these types are declared as Bit or Bit-String types.
+        switch (s7Field.getDataType()) {
+            case BYTE:
+            case SINT:
+            case USINT:
+            case CHAR:
+                return internalEncodeInteger(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeShort(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case WORD:
+            case INT:
+            case UINT:
+                return internalEncodeInteger(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeInteger(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case DWORD:
+            case DINT:
+            case UDINT:
+                return internalEncodeInteger(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeBigInteger(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case DWORD:
+            case DINT:
+            case UDINT:
+                return internalEncodeInteger(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeLong(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case LWORD:
+            case LINT:
+            case ULINT:
+                return internalEncodeInteger(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeFloat(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case REAL:
+                return internalEncodeFloatingPoint(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeDouble(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case LREAL:
+                return internalEncodeFloatingPoint(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeString(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case CHAR:
+            case WCHAR:
+            case STRING:
+            case WSTRING:
+                return internalEncodeString(field, values);
+            default:
+                throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name());
+        }
+    }
+
+    @Override
+    public BaseDefaultFieldItem 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 BaseDefaultFieldItem 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 BaseDefaultFieldItem 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 BaseDefaultFieldItem internalEncodeBoolean(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case BOOL:
+            case BYTE:
+            case WORD:
+            case DWORD:
+            case LWORD:
+                break;
+            default:
+                throw new IllegalArgumentException(
+                    "Cannot assign boolean values to " + s7Field.getDataType().name() + " fields.");
+        }
+        List<Boolean> booleanValues = new LinkedList<>();
+        for (Object value : values) {
+            if (value instanceof Boolean) {
+                Boolean booleanValue = (Boolean) value;
+                booleanValues.add(booleanValue);
+            } else if (value instanceof Byte) {
+                Byte byteValue = (Byte) value;
+                BitSet bitSet = BitSet.valueOf(new byte[]{byteValue});
+                for (int i = 0; i < 8; i++) {
+                    booleanValues.add(bitSet.get(i));
+                }
+            } else if (value instanceof Short) {
+                Short shortValue = (Short) value;
+                BitSet bitSet = BitSet.valueOf(new long[]{shortValue});
+                for (int i = 0; i < 16; i++) {
+                    booleanValues.add(bitSet.get(i));
+                }
+            } else if (value instanceof Integer) {
+                Integer integerValue = (Integer) value;
+                BitSet bitSet = BitSet.valueOf(new long[]{integerValue});
+                for (int i = 0; i < 32; i++) {
+                    booleanValues.add(bitSet.get(i));
+                }
+            } else if (value instanceof Long) {
+                long longValue = (Long) value;
+                BitSet bitSet = BitSet.valueOf(new long[]{longValue});
+                for (int i = 0; i < 64; i++) {
+                    booleanValues.add(bitSet.get(i));
+                }
+            } else {
+                throw new IllegalArgumentException(
+                    "Value of type " + value.getClass().getName() +
+                        " is not assignable to " + s7Field.getDataType().name() + " fields.");
+            }
+        }
+        return new DefaultBooleanFieldItem(booleanValues.toArray(new Boolean[0]));
+    }
+
+    private BaseDefaultFieldItem internalEncodeInteger(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+
+        // Initialize the constraints.
+        BigInteger minValue;
+        BigInteger maxValue;
+        Class<? extends BaseDefaultFieldItem> fieldType;
+        Class<?> valueType;
+        Object[] castedValues;
+        switch (s7Field.getDataType()) {
+            case BYTE:
+                minValue = BigInteger.valueOf((long) Byte.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Byte.MAX_VALUE);
+                fieldType = DefaultByteFieldItem.class;
+                valueType = Byte[].class;
+                castedValues = new Byte[values.length];
+                break;
+            case WORD:
+                minValue = BigInteger.valueOf((long) Short.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Short.MAX_VALUE);
+                fieldType = DefaultShortFieldItem.class;
+                valueType = Short[].class;
+                castedValues = new Short[values.length];
+                break;
+            case DWORD:
+                minValue = BigInteger.valueOf((long) Integer.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Integer.MAX_VALUE);
+                fieldType = DefaultIntegerFieldItem.class;
+                valueType = Integer[].class;
+                castedValues = new Integer[values.length];
+                break;
+            case LWORD:
+                minValue = BigInteger.valueOf(Long.MIN_VALUE);
+                maxValue = BigInteger.valueOf(Long.MAX_VALUE);
+                fieldType = DefaultLongFieldItem.class;
+                valueType = Long[].class;
+                castedValues = new Long[values.length];
+                break;
+            case SINT:
+                minValue = BigInteger.valueOf((long) Byte.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Byte.MAX_VALUE);
+                fieldType = DefaultByteFieldItem.class;
+                valueType = Byte[].class;
+                castedValues = new Byte[values.length];
+                break;
+            case USINT:
+                minValue = BigInteger.valueOf((long) 0);
+                maxValue = BigInteger.valueOf((long) Byte.MAX_VALUE * 2);
+                fieldType = DefaultShortFieldItem.class;
+                valueType = Short[].class;
+                castedValues = new Short[values.length];
+                break;
+            case INT:
+                minValue = BigInteger.valueOf((long) Short.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Short.MAX_VALUE);
+                fieldType = DefaultShortFieldItem.class;
+                valueType = Short[].class;
+                castedValues = new Short[values.length];
+                break;
+            case UINT:
+                minValue = BigInteger.valueOf((long) 0);
+                maxValue = BigInteger.valueOf(((long) Short.MAX_VALUE) * 2);
+                fieldType = DefaultIntegerFieldItem.class;
+                valueType = Integer[].class;
+                castedValues = new Integer[values.length];
+                break;
+            case DINT:
+                minValue = BigInteger.valueOf((long) Integer.MIN_VALUE);
+                maxValue = BigInteger.valueOf((long) Integer.MAX_VALUE);
+                fieldType = DefaultIntegerFieldItem.class;
+                valueType = Integer[].class;
+                castedValues = new Integer[values.length];
+                break;
+            case UDINT:
+                minValue = BigInteger.valueOf((long) 0);
+                maxValue = BigInteger.valueOf(((long) Integer.MAX_VALUE) * 2);
+                fieldType = DefaultLongFieldItem.class;
+                valueType = Long[].class;
+                castedValues = new Long[values.length];
+                break;
+            case LINT:
+                minValue = BigInteger.valueOf(Long.MIN_VALUE);
+                maxValue = BigInteger.valueOf(Long.MAX_VALUE);
+                fieldType = DefaultLongFieldItem.class;
+                valueType = Long[].class;
+                castedValues = new Long[values.length];
+                break;
+            case ULINT:
+                minValue = BigInteger.valueOf((long) 0);
+                maxValue = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf((long) 2));
+                fieldType = DefaultBigIntegerFieldItem.class;
+                valueType = BigInteger[].class;
+                castedValues = new BigInteger[values.length];
+                break;
+            default:
+                throw new IllegalArgumentException(
+                    "Cannot assign integer values to " + s7Field.getDataType().name() + " fields.");
+        }
+
+        // Check the constraints
+        for (int i = 0; i < values.length; i++) {
+            BigInteger value;
+            if (values[i] instanceof BigInteger) {
+                value = (BigInteger) values[i];
+            } else if ((values[i] instanceof Byte) || (values[i] instanceof Short) ||
+                (values[i] instanceof Integer) || (values[i] instanceof Long)) {
+                value = BigInteger.valueOf(((Number) values[i]).longValue());
+            } else {
+                throw new IllegalArgumentException(
+                    "Value of type " + values[i].getClass().getName() +
+                        " is not assignable to " + s7Field.getDataType().name() + " fields.");
+            }
+            if (minValue.compareTo(value) > 0) {
+                throw new IllegalArgumentException(
+                    "Value of " + value.toString() + " exceeds allowed minimum for type "
+                        + s7Field.getDataType().name() + " (min " + minValue.toString() + ")");
+            }
+            if (maxValue.compareTo(value) < 0) {
+                throw new IllegalArgumentException(
+                    "Value of " + value.toString() + " exceeds allowed maximum for type "
+                        + s7Field.getDataType().name() + " (max " + maxValue.toString() + ")");
+            }
+            if (valueType == Byte[].class) {
+                castedValues[i] = value.byteValue();
+            } else if (valueType == Short[].class) {
+                castedValues[i] = value.shortValue();
+            } else if (valueType == Integer[].class) {
+                castedValues[i] = value.intValue();
+            } else if (valueType == Long[].class) {
+                castedValues[i] = value.longValue();
+            } else {
+                castedValues[i] = value;
+            }
+        }
+
+        // Create the field item.
+        try {
+            return fieldType.getDeclaredConstructor(valueType).newInstance(new Object[]{castedValues});
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            throw new PlcRuntimeException("Error initializing field class " + fieldType.getSimpleName(), e);
+        }
+    }
+
+    private BaseDefaultFieldItem internalEncodeFloatingPoint(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+
+        // Initialize the constraints.
+        Double minValue;
+        Double maxValue;
+        Class<? extends BaseDefaultFieldItem> fieldType;
+        Class<?> valueType;
+        Object[] castedValues;
+        switch (s7Field.getDataType()) {
+            case REAL:
+                minValue = (double) -Float.MAX_VALUE;
+                maxValue = (double) Float.MAX_VALUE;
+                fieldType = DefaultFloatFieldItem.class;
+                valueType = Float[].class;
+                castedValues = new Float[values.length];
+                break;
+            case LREAL:
+                minValue = -Double.MAX_VALUE;
+                maxValue = Double.MAX_VALUE;
+                fieldType = DefaultDoubleFieldItem.class;
+                valueType = Double[].class;
+                castedValues = new Double[values.length];
+                break;
+            default:
+                throw new IllegalArgumentException(
+                    "Cannot assign floating point values to " + s7Field.getDataType().name() + " fields.");
+        }
+
+        // Check the constraints
+        for (int i = 0; i < values.length; i++) {
+            Double value;
+            if (values[i] instanceof Float) {
+                value = ((Float) values[i]).doubleValue();
+            } else if (values[i] instanceof Double) {
+                value = (Double) values[i];
+            } else {
+                throw new IllegalArgumentException(
+                    "Value of type " + values[i].getClass().getName() +
+                        " is not assignable to " + s7Field.getDataType().name() + " fields.");
+            }
+            if (value < minValue) {
+                throw new IllegalArgumentException(
+                    "Value of " + value + " exceeds allowed minimum for type "
+                        + s7Field.getDataType().name() + " (min " + minValue.toString() + ")");
+            }
+            if (value > maxValue) {
+                throw new IllegalArgumentException(
+                    "Value of " + value + " exceeds allowed maximum for type "
+                        + s7Field.getDataType().name() + " (max " + maxValue.toString() + ")");
+            }
+            if (valueType == Float[].class) {
+                castedValues[i] = value.floatValue();
+            } else {
+                castedValues[i] = value;
+            }
+        }
+
+        // Create the field item.
+        try {
+            return fieldType.getDeclaredConstructor(valueType).newInstance(new Object[]{castedValues});
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            throw new PlcRuntimeException("Error initializing field class " + fieldType.getSimpleName(), e);
+        }
+    }
+
+    private BaseDefaultFieldItem internalEncodeString(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+
+        // Initialize the constraints.
+        int maxLength;
+        boolean encoding16Bit;
+        switch (s7Field.getDataType()) {
+            case CHAR:
+                maxLength = 1;
+                encoding16Bit = false;
+                break;
+            case WCHAR:
+                maxLength = 1;
+                encoding16Bit = true;
+                break;
+            case STRING:
+                maxLength = 254;
+                encoding16Bit = false;
+                break;
+            case WSTRING:
+                maxLength = 254;
+                encoding16Bit = true;
+                break;
+            default:
+                throw new IllegalArgumentException(
+                    "Cannot assign string values to " + s7Field.getDataType().name() + " fields.");
+        }
+
+        // Check the constraints and create the strings.
+        List<String> stringValues = new LinkedList<>();
+        for (Object value : values) {
+            if (value instanceof String) {
+                String stringValue = (String) value;
+                if (stringValue.length() > maxLength) {
+                    throw new IllegalArgumentException(
+                        "String length " + stringValue.length() + " exceeds allowed maximum for type "
+                            + s7Field.getDataType().name() + " (max " + maxLength + ")");
+                }
+                stringValues.add(stringValue);
+            }
+            // All other types just translate to max one String character.
+            else if (value instanceof Byte) {
+                Byte byteValue = (Byte) value;
+                byte[] stringBytes = new byte[]{byteValue};
+                if (encoding16Bit) {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
+                } else {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                }
+            } else if (value instanceof Short) {
+                Short shortValue = (Short) value;
+                byte[] stringBytes = new byte[2];
+                stringBytes[0] = (byte) (shortValue >> 8);
+                stringBytes[1] = (byte) (shortValue & 0xFF);
+                if (encoding16Bit) {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
+                } else {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                }
+            } else if (value instanceof Integer) {
+                Integer integerValue = (Integer) value;
+                byte[] stringBytes = new byte[4];
+                stringBytes[0] = (byte) ((integerValue >> 24) & 0xFF);
+                stringBytes[1] = (byte) ((integerValue >> 16) & 0xFF);
+                stringBytes[2] = (byte) ((integerValue >> 8) & 0xFF);
+                stringBytes[3] = (byte) (integerValue & 0xFF);
+                if (encoding16Bit) {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
+                } else {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                }
+            } else if (value instanceof Long) {
+                Long longValue = (Long) value;
+                byte[] stringBytes = new byte[8];
+                stringBytes[0] = (byte) ((longValue >> 56) & 0xFF);
+                stringBytes[1] = (byte) ((longValue >> 48) & 0xFF);
+                stringBytes[2] = (byte) ((longValue >> 40) & 0xFF);
+                stringBytes[3] = (byte) ((longValue >> 32) & 0xFF);
+                stringBytes[4] = (byte) ((longValue >> 24) & 0xFF);
+                stringBytes[5] = (byte) ((longValue >> 16) & 0xFF);
+                stringBytes[6] = (byte) ((longValue >> 8) & 0xFF);
+                stringBytes[7] = (byte) (longValue & 0xFF);
+                if (encoding16Bit) {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_16));
+                } else {
+                    stringValues.add(new String(stringBytes, StandardCharsets.UTF_8));
+                }
+            } else {
+                throw new IllegalArgumentException(
+                    "Value of type " + value.getClass().getName() +
+                        " is not assignable to " + s7Field.getDataType().name() + " fields.");
+            }
+        }
+
+        // Create the field item.
+        return new DefaultStringFieldItem(stringValues.toArray(new String[0]));
+    }
+
+    private BaseDefaultFieldItem internalEncodeTemporal(PlcField field, Object[] values) {
+        S7Field s7Field = (S7Field) field;
+        switch (s7Field.getDataType()) {
+            case TIME:
+                // TODO: I think I should implement this some time ...
+            case DATE:
+                // TODO: I think I should implement this some time ...
+            case DATE_AND_TIME:
+                return new DefaultLocalDateTimeFieldItem();
+            default:
+                throw new IllegalArgumentException(
+                    "Cannot assign temporal values to " + s7Field.getDataType().name() + " fields.");
+        }
+    }
+
+}
diff --git a/src/site/asciidoc/protocols/delta-v/reverse-engineering.adoc b/src/site/asciidoc/protocols/delta-v/reverse-engineering.adoc
index f62ed1e..f41e046 100644
--- a/src/site/asciidoc/protocols/delta-v/reverse-engineering.adoc
+++ b/src/site/asciidoc/protocols/delta-v/reverse-engineering.adoc
@@ -234,7 +234,7 @@ With this we were able to write a simple console application that was able to in
 
 However when using what we learnt on the old captures we did, it turned out that unfortunately we could no longer find these `0x0b08` sequences, however we did find a lot of `0x08` followed by a 32 bit floating point value.
 So it seems that `0x08` indicates the type of an `signed 32 bit IEE 754 floating point value`.
-Eventually the `0x0b` part referred to some sort subscription-id.
+Perhaps the `0x0b` part referred to some sort subscription-id.
 
 As we seem to be doing a subscription based communication, the OS has to tell the controller what information it is interested in.
 
diff --git a/src/site/asciidoc/protocols/s7/s7comm-plus.adoc b/src/site/asciidoc/protocols/s7/s7comm-plus.adoc
index a4178e3..7be68b0 100644
--- a/src/site/asciidoc/protocols/s7/s7comm-plus.adoc
+++ b/src/site/asciidoc/protocols/s7/s7comm-plus.adoc
@@ -31,7 +31,7 @@ Beyond that, it seems that implementing this protocol would require knowledge of
 As we can't reverse-engineer these keys, the only way we could get them, would be by disassembling the existing code, which would not be allowed.
 
 Therefore we have currently stopped working on this protocol type.
-Eventually things may change in the future, but for now we see no way we could finish this on a legally correct path.
+Probably things may change in the future, but for now we see no way we could finish this on a legally correct path.
 
 == Links