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/07 21:30:06 UTC

[incubator-plc4x] branch develop updated (4d7ff5a -> 6c49277)

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

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


    from 4d7ff5a  Commented the timeout back in again (Wasn't reducing the number of kills) .. I am assuming it's due to some OS limitation and usually occurs with parallel executed builds.
     new 66aebb3  - Continued working on the dynamic s7 driver
     new 6c49277  - Continued working on the dynamic s7 driver

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/plc4x/protocols/s7/protocol.dfdl.xsd    |   2 +-
 .../apache/plc4x/protocols/s7/protocol.scxml.xml   | 265 ++++++++++----------
 .../org/apache/plc4x/protocols/s7/protocol.tdml    |   4 +-
 .../pom.xml                                        |  53 ++--
 .../java/dynamic/actions/BaseConnectedAction.java  |  17 +-
 .../java/dynamic/actions/BaseDaffodilAction.java}  |  24 +-
 .../java/dynamic/actions/BasePlc4xAction.java      |  52 ++++
 .../java/dynamic}/actions/ConnectAction.java       |  25 +-
 .../java/dynamic}/actions/InitContextAction.java   |  63 ++---
 .../java/dynamic/actions/ReceiveAction.java        | 266 +++++++++++++++++++++
 .../sandbox/java/dynamic}/actions/SendAction.java  |  27 +--
 .../connection/DynamicDriverConnectionBase.java    | 134 +++++++++++
 .../utils/W3CDOMTemplateInfosetInputter.scala      |  42 ++++
 sandbox/dynamic-driver-s7/pom.xml                  |  14 ++
 .../sandbox/java/dynamic/s7/DynamicS7Driver.java   |  54 ++---
 .../plc4x/sandbox/java/{ => dynamic}/s7/Poc.java   |  48 +++-
 .../dynamic/s7/actions/S7DecodeArticleNumber.java  |  91 +++++++
 .../dynamic/s7/connection/DynamicS7Connection.java | 167 +++++++++++++
 .../java/dynamic/s7/utils/S7TsapIdEncoder.java     |  55 ++---
 .../sandbox/java/s7/actions/ReceiveAction.java     | 145 -----------
 .../services/org.apache.plc4x.java.spi.PlcDriver   |   2 +-
 sandbox/pom.xml                                    |   1 +
 22 files changed, 1084 insertions(+), 467 deletions(-)
 copy sandbox/{dynamic-driver-s7 => dynamic-driver-base}/pom.xml (68%)
 copy plc4j/drivers/simulated/src/main/java/org/apache/plc4x/java/simulated/connection/TestFieldItem.java => sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseConnectedAction.java (66%)
 rename sandbox/{dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java => dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseDaffodilAction.java} (72%)
 create mode 100644 sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
 rename sandbox/{dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7 => dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic}/actions/ConnectAction.java (75%)
 rename sandbox/{dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7 => dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic}/actions/InitContextAction.java (53%)
 create mode 100644 sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
 rename sandbox/{dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7 => dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic}/actions/SendAction.java (73%)
 create mode 100644 sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java
 create mode 100644 sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
 copy plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/S7PlcDriver.java => sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java (56%)
 rename sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/{ => dynamic}/s7/Poc.java (59%)
 create mode 100644 sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeArticleNumber.java
 create mode 100644 sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java
 copy plc4j/protocols/driver-bases/base/src/test/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequestTest.java => sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7TsapIdEncoder.java (54%)
 delete mode 100644 sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
 copy {plc4j/drivers/simulated => sandbox/dynamic-driver-s7}/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver (96%)


[incubator-plc4x] 01/02: - Continued working on the dynamic s7 driver

Posted by cd...@apache.org.
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

commit 66aebb38a350411a25dfa149ce996a992924905f
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Feb 7 15:22:50 2019 +0100

    - Continued working on the dynamic s7 driver
    
    (In it's current state it is able to connect to a remote PLC and identify the type)
---
 .../apache/plc4x/protocols/s7/protocol.dfdl.xsd    |   2 +-
 .../apache/plc4x/protocols/s7/protocol.scxml.xml   | 248 +++++++++------------
 .../org/apache/plc4x/protocols/s7/protocol.tdml    |   4 +-
 sandbox/dynamic-driver-s7/pom.xml                  |  32 +++
 .../java/org/apache/plc4x/sandbox/java/s7/Poc.java |  32 ++-
 .../java/s7/actions/BaseConnectedAction.java       |  34 +++
 ...asePlc4xAction.java => BaseDaffodilAction.java} |  22 +-
 .../sandbox/java/s7/actions/BasePlc4xAction.java   |  58 ++---
 .../sandbox/java/s7/actions/ConnectAction.java     |  23 +-
 .../sandbox/java/s7/actions/InitContextAction.java |  61 ++---
 .../sandbox/java/s7/actions/ReceiveAction.java     | 191 +++++++++++++---
 .../plc4x/sandbox/java/s7/actions/SendAction.java  |  25 +--
 .../java/s7/actions/s7/S7DecodeArticleNumber.java  |  91 ++++++++
 .../s7/utils/W3CDOMTemplateInfosetInputter.scala   |  42 ++++
 14 files changed, 571 insertions(+), 294 deletions(-)

diff --git a/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.dfdl.xsd b/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.dfdl.xsd
index 07715ab..b0ec9f8 100644
--- a/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.dfdl.xsd
+++ b/protocols/s7/src/main/resources/org/apache/plc4x/protocols/s7/protocol.dfdl.xsd
@@ -177,7 +177,7 @@
             </xs:choice>
             <xs:element name="userData" type="s7:S7MessageType" minOccurs="0"
                         dfdl:occursCountKind="expression"
-                        dfdl:occursCount="{if((../../length - (../headerLength + 1)) gt 0) then 1 else 0}"/>
+                        dfdl:occursCount="{if((../../length - (../headerLength + 5)) gt 0) then 1 else 0}"/>
         </xs:sequence>
     </xs:complexType>
 
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 e272f77..bfab15c 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
@@ -25,25 +25,42 @@
           datamodel="jexl"
           xsi:schemaLocation="http://www.w3.org/2005/07/scxml http://www.w3.org/2011/04/SCXML/scxml.xsd">
 
+  <!-- Define all the variables we're going to use -->
   <sc:datamodel>
-    <sc:data id="args"/>
+    <sc:data id="protocolDaffodilSchema"/>
+    <sc:data id="cotpLocalReference"/>
+    <sc:data id="cotpCalledTsap"/>
+    <sc:data id="cotpCallingTsap"/>
+    <sc:data id="cotpTpduSize"/>
+    <sc:data id="s7MaxAmqCaller"/>
+    <sc:data id="s7MaxAmqCallee"/>
+    <sc:data id="s7PduLength"/>
+    <sc:data id="s7ArticleNumber"/>
+    <sc:data id="plcType"/>
   </sc:datamodel>
 
+  <!--
+    Setup the initial state ... this usually just initializes the Daffodil subsystem.
+  -->
   <sc:state id="init">
     <sc:onentry>
       <!-- Setup the initial content of the connection context (Callback in the driver) -->
-      <plc4x:initContext/>
+      <plc4x:initContext protocolDaffodilSchemaName="protocolDaffodilSchema"/>
     </sc:onentry>
     <sc:transition event="success" target="connect">
       <sc:assign location="args" expr="_event.data"/>
     </sc:transition>
   </sc:state>
 
+  <!--
+    Sub-Statemachine handling the connection establishment.
+  -->
   <sc:state id="connect">
     <sc:initial>
       <sc:transition target="establishNetworkConnection"/>
     </sc:initial>
 
+    <!-- This step establishes the physical connection to the remote -->
     <sc:state id="establishNetworkConnection">
       <sc:onentry>
         <!-- Initialize the network connection to the remote host using the tcp adapter with a given host and port -->
@@ -53,9 +70,20 @@
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      First we have to connect on COTP level, so send CTOP connection request first.
+      Some parameters we are sending are a suggestion from our side, the remote will
+      respond with values it sees more fitting.
+
+      For example the "called-tsap" we just make up an id and the remote will respond
+      with its real id.
+
+      The pdu size is the one is the maximum PDU size we can live with, the remote
+      will respond with a size that is at most this big (usually it's smaller).
+    -->
     <sc:state id="sendCotpConnectionRequest">
       <sc:onentry>
-        <plc4x:send socketParameterName="connection">
+        <plc4x:send>
           <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
@@ -65,29 +93,29 @@
               <type>224</type>
               <s7:CotpTpduConnectionRequest>
                 <destinationReference>0</destinationReference>
-                <!-- Insert the value for "cotp-local-reference" as short here -->
-                <sourceReference>15</sourceReference><!--plc4x:insert type="s7:short" name="cotp-local-reference"/-->
+                <!-- Insert the value for "cotpLocalReference" as short here -->
+                <sourceReference>${cotpLocalReference}</sourceReference>
                 <protocolClass>0</protocolClass>
                 <s7:parameters>
                   <parameter>
                     <type>194</type>
                     <parameterLength>2</parameterLength>
                     <s7:CotpParameterCalledTsap>
-                      <tsapId>512</tsapId><!--plc4x:insert type="s7:short" name="cotp-called-tsap"/-->
+                      <tsapId>${cotpCalledTsap}</tsapId>
                     </s7:CotpParameterCalledTsap>
                   </parameter>
                   <parameter>
                     <type>193</type>
                     <parameterLength>2</parameterLength>
                     <s7:CotpParameterCallingTsap>
-                      <tsapId>273</tsapId><!--plc4x:insert type="s7:short" name="cotp-calling-tsap"/-->
+                      <tsapId>${cotpCallingTsap}</tsapId>
                     </s7:CotpParameterCallingTsap>
                   </parameter>
                   <parameter>
                     <type>192</type>
                     <parameterLength>1</parameterLength>
                     <s7:CotpParameterTpduSize>
-                      <tpduSize>10</tpduSize><!--plc4x:insert type="s7:byte" name="cotp-tpdu-size"/-->
+                      <tpduSize>${cotpTpduSize}</tpduSize>
                     </s7:CotpParameterTpduSize>
                   </parameter>
                 </s7:parameters>
@@ -100,23 +128,33 @@
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      If everything wen't fine, the remote should respond with a connection response.
+      As mentioned before we now have to update some of the values with the ones the
+      remote responded with.
+    -->
     <sc:state id="receiveCotpConnectionResponse">
       <sc:onentry>
-        <plc4x:receive socketParameterName="connection" timeout="5000">
-          <verification name="cotp-local-reference" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/destinationReference"/>
-          <extraction name="cotp-remote-reference" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/sourceReference"/>
-          <extraction name="cotp-tpdu-size" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterTpduSize/tpduSize"/>
-          <extraction name="cotp-calling-tsap" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterCallingTsap/tsapId"/>
-          <extraction name="cotp-called-tsap" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/s7:parameters/parameter/s7:CotpParameterCalledTsap/tsapId"/>
+        <plc4x:receive 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>
       </sc:onentry>
       <sc:transition event="success" target="sendS7SetupCommunicationRequest"/>
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      After the connection is established on COTP level, we now do the same on the S7
+      protocol level. Again we will be sending values we think are ok and in the
+      response the remote will tell us what it can live with.
+    -->
     <sc:state id="sendS7SetupCommunicationRequest">
       <sc:onentry>
-        <plc4x:send socketParameterName="connection">
+        <plc4x:send>
           <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
@@ -136,17 +174,17 @@
                   <tpduReference>0</tpduReference>
                   <parametersLength>8</parametersLength>
                   <payloadsLength>0</payloadsLength>
-                  <s7:parameters>
+                  <parameters>
                     <parameter>
                       <type>240</type>
                       <s7:S7GeneralParameterSetupCommunication>
                         <reserved>0</reserved>
-                        <maxAmqCaller>10</maxAmqCaller><!--plc4x:insert type="s7:short" name="s7-max-amq-caller"/-->
-                        <maxAmqCallee>10</maxAmqCallee><!--plc4x:insert type="s7:short" name="s7-max-amq-callee"/-->
-                        <pduLength>1024</pduLength><!--plc4x:insert type="s7:short" name="s7-pdu-length"/-->
+                        <maxAmqCaller>${s7MaxAmqCaller}</maxAmqCaller>
+                        <maxAmqCallee>${s7MaxAmqCallee}</maxAmqCallee>
+                        <pduLength>${s7PduLength}</pduLength>
                       </s7:S7GeneralParameterSetupCommunication>
                     </parameter>
-                  </s7:parameters>
+                  </parameters>
                   <payloads>
                     <payload>
                       <s7:S7GeneralPayloadSetupCommunication/>
@@ -162,24 +200,38 @@
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      If everything wen't fine, the remote should respond with a connection response.
+      As mentioned before we now have to update some of the values with the ones the
+      remote responded with.
+
+      If a "plcType" was provided, we are now connected.
+
+      If no "plcType" was provided, the type has to be discovered by sending another
+      request and processing that response first.
+    -->
     <sc:state id="receiveS7SetupCommunicationResponse">
       <sc:onentry>
-        <plc4x:receive socketParameterName="connection" timeout="5000">
-          <verification name="cotp-local-reference" xpath="s7:TpktMessage/userData/s7:CotpTpduConnectionResponse/destinationReference"/>
-          <extraction name="returnCode" xpath="s7:TpktMessage/userData/userData/s7:S7ResponseMessage/errorCode"/>
-          <extraction name="s7-max-amq-caller" xpath="s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/s7:S7GeneralParameterSetupCommunication/maxAmqCaller"/>
-          <extraction name="s7-max-amq-callee" xpath="s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/s7:S7GeneralParameterSetupCommunication/maxAmqCallee"/>
-          <extraction name="s7-pdu-length" xpath="s7:TpktMessage/userData/userData/s7:S7ResponseMessage/parameters/s7:S7GeneralParameterSetupCommunication/pduLength"/>
+        <plc4x:receive 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>
       </sc:onentry>
-      <sc:transition event="" target="sendS7IdentificationRequest"/>
-      <sc:transition event="success" target="connected"/>
+      <sc:transition event="success" cond="plcType == null" target="sendS7IdentificationRequest"/>
+      <sc:transition event="success" cond="plcType != null" target="connected"/>
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      If no "plcType" was provided, an S7 identification request will ask the
+      remote to send back so-called SSLs. These contain information on the type
+      and version of the remote PLC.
+    -->
     <sc:state id="sendS7IdentificationRequest">
       <sc:onentry>
-        <plc4x:send socketParameterName="connection">
+        <plc4x:send>
           <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
@@ -199,7 +251,7 @@
                   <tpduReference>256</tpduReference>
                   <parametersLength>8</parametersLength>
                   <payloadsLength>8</payloadsLength>
-                  <s7:parameters>
+                  <parameters>
                     <parameter>
                       <type>0</type>
                       <s7:S7UserDataParameterCPUService>
@@ -212,7 +264,7 @@
                         <sequenceNumber>0</sequenceNumber>
                       </s7:S7UserDataParameterCPUService>
                     </parameter>
-                  </s7:parameters>
+                  </parameters>
                   <payloads>
                     <payload>
                       <s7:S7UserDataPayloadCpuServices>
@@ -234,130 +286,50 @@
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      As we're currently only interested in the type of the PLC, we simply
+      take the article number returned and decode that in a S7 specific
+      custom action.
+    -->
     <sc:state id="receiveS7IdentificationRequest">
       <sc:onentry>
-        <plc4x:receive socketParameterName="connection">
-          <s7:TpktMessage>
-            <magicByte>3</magicByte>
-            <reserved>0</reserved>
-            <length><plc4x:ignore/></length>
-            <userData>
-              <headerLength>2</headerLength>
-              <type>240</type>
-              <s7:CotpTpduData>
-                <endOfTransmission>1</endOfTransmission>
-                <tpduRef>0</tpduRef>
-              </s7:CotpTpduData>
-              <userData>
-                <magicByte>50</magicByte>
-                <type>7</type>
-                <s7:S7UserDataMessage>
-                  <reserved>0</reserved>
-                  <tpduReference>256</tpduReference>
-                  <parametersLength><plc4x:ignore/></parametersLength>
-                  <payloadsLength><plc4x:ignore/></payloadsLength>
-                  <s7:parameters>
-                    <plc4x:unordered>
-                      <parameter>
-                        <type>0</type>
-                        <S7UserDataParameterCPUService>
-                          <header>274</header>
-                          <paramLength>8</paramLength>
-                          <typeCode>18</typeCode>
-                          <type>8</type>
-                          <functionGroup>4</functionGroup>
-                          <subFunctionGroup>1</subFunctionGroup>
-                          <sequenceNumber>2</sequenceNumber>
-                          <dataUnitReferenceNumber>0</dataUnitReferenceNumber>
-                          <lastDataUnit>0</lastDataUnit>
-                          <errorCode>0</errorCode>
-                        </S7UserDataParameterCPUService>
-                      </parameter>
-                      <plc4x:ignore/>
-                    </plc4x:unordered>
-                  </s7:parameters>
-                  <payloads>
-                    <plc4x:unordered>
-                      <payload>
-                        <S7UserDataPayloadCpuServices>
-                          <returnCode>255</returnCode>
-                          <transportSize>9</transportSize>
-                          <length>120</length>
-                          <sslId>17</sslId>
-                          <sslIndex>0</sslIndex>
-                          <partialList>
-                            <partialListLengthInBytes>28</partialListLengthInBytes>
-                            <partialListCount>4</partialListCount>
-                            <sslDataRecords>
-                              <plc4x:unordered>
-                                <sslDataRecord>
-                                  <S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                    <index>1</index>
-                                    <articleNumber><plc4x:extract type="s7:short" name="s7-ssl-1"/></articleNumber>
-                                    <bgType>192</bgType>
-                                    <moduleOrOsVersion>3</moduleOrOsVersion>
-                                    <pgDescriptionFileVersion>1</pgDescriptionFileVersion>
-                                  </S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                </sslDataRecord>
-                                <sslDataRecord>
-                                  <S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                    <index>6</index>
-                                    <articleNumber><plc4x:extract type="s7:short" name="s7-ssl-6"/></articleNumber>
-                                    <bgType>192</bgType>
-                                    <moduleOrOsVersion>3</moduleOrOsVersion>
-                                    <pgDescriptionFileVersion>1</pgDescriptionFileVersion>
-                                  </S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                </sslDataRecord>
-                                <sslDataRecord>
-                                  <S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                    <index>7</index>
-                                    <articleNumber><plc4x:extract type="s7:short" name="s7-ssl-7"/></articleNumber>
-                                    <bgType>192</bgType>
-                                    <moduleOrOsVersion>22019</moduleOrOsVersion>
-                                    <pgDescriptionFileVersion>519</pgDescriptionFileVersion>
-                                  </S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                </sslDataRecord>
-                                <sslDataRecord>
-                                  <S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                    <index>129</index>
-                                    <articleNumber><plc4x:extract type="s7:short" name="s7-ssl-129"/></articleNumber>
-                                    <bgType>0</bgType>
-                                    <moduleOrOsVersion>16672</moduleOrOsVersion>
-                                    <pgDescriptionFileVersion>2313</pgDescriptionFileVersion>
-                                  </S7ResponsePayloadCpuServicesSslDataRecordModuleIdentification>
-                                </sslDataRecord>
-                                <plc4x:ignore/>
-                              </plc4x:unordered>
-                            </sslDataRecords>
-                          </partialList>
-                        </S7UserDataPayloadCpuServices>
-                      </payload>
-                      <plc4x:ignore/>
-                    </plc4x:unordered>
-                  </payloads>
-                </s7:S7UserDataMessage>
-              </userData>
-            </userData>
-          </s7:TpktMessage>
+        <plc4x:receive 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>
       </sc:onentry>
-      <sc:transition event="success" target="connected"/>
+      <sc:transition event="success" target="connected">
+        <plc4x:S7DecodeArticleNumber articleNumberParameterName="s7ArticleNumber" plcTypeParameterName="plcType"/>
+      </sc:transition>
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
+    <!--
+      Default state after connecting to a PLC.
+    -->
     <sc:state id="connected">
       <sc:onentry>
-        <sc:log expr="'Connected'"/>
+        <sc:log expr="'Connected to PLC of type: ' + plcType"/>
       </sc:onentry>
     </sc:state>
 
+    <!--
+      Final state of this state-machine, after any of the parties disconnected.
+    -->
     <sc:final id="disconnected">
-
+      <sc:onentry>
+        <sc:log expr="'Disconnected'"/>
+      </sc:onentry>
     </sc:final>
 
+    <!--
+      Error state in case of any form of error during the processing of data.
+    -->
     <sc:final id="error">
       <sc:onentry>
-        <sc:log expr="'Error connecting'"/>
+        <sc:log expr="'Error'"/>
       </sc:onentry>
     </sc:final>
   </sc:state>
diff --git a/protocols/s7/src/test/resources/org/apache/plc4x/protocols/s7/protocol.tdml b/protocols/s7/src/test/resources/org/apache/plc4x/protocols/s7/protocol.tdml
index e9aff9f..c418628 100644
--- a/protocols/s7/src/test/resources/org/apache/plc4x/protocols/s7/protocol.tdml
+++ b/protocols/s7/src/test/resources/org/apache/plc4x/protocols/s7/protocol.tdml
@@ -49,7 +49,7 @@
                          description="Simple TKPT packet which contains a COTP Connection-Response as payload.">
         <!-- Define the input -->
         <tdml:document>
-            <tdml:documentPart type="byte">0300001211D00001000200C00109C1020100C2020102</tdml:documentPart>
+            <tdml:documentPart type="byte">0300001611D00001000200C00109C1020100C2020102</tdml:documentPart>
         </tdml:document>
 
         <!-- Define the expected output -->
@@ -59,7 +59,7 @@
                 <test:tpktMessage>
                     <magicByte>3</magicByte>
                     <reserved>0</reserved>
-                    <length>18</length>
+                    <length>22</length>
                     <userData>
                         <headerLength>17</headerLength>
                         <type>208</type>
diff --git a/sandbox/dynamic-driver-s7/pom.xml b/sandbox/dynamic-driver-s7/pom.xml
index 9e99f0a..f302333 100644
--- a/sandbox/dynamic-driver-s7/pom.xml
+++ b/sandbox/dynamic-driver-s7/pom.xml
@@ -58,6 +58,11 @@
       <artifactId>xml-apis</artifactId>
       <version>1.4.01</version>
     </dependency>
+    <dependency>
+      <groupId>jaxen</groupId>
+      <artifactId>jaxen</artifactId>
+      <version>1.1.6</version>
+    </dependency>
 
     <dependency>
       <groupId>org.slf4j</groupId>
@@ -74,6 +79,33 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>net.alchim31.maven</groupId>
+        <artifactId>scala-maven-plugin</artifactId>
+        <version>3.4.6</version>
+        <executions>
+          <execution>
+            <id>add-scala-sources</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sourceDir>src/main/scala</sourceDir>
+            </configuration>
+          </execution>
+          <execution>
+            <id>compile-scala</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+            <configuration>
+              <outputDir>${project.build.outputDirectory}</outputDir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <configuration>
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java
index 790f2ef..04faee4 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java
@@ -30,15 +30,22 @@ import org.apache.plc4x.sandbox.java.s7.actions.ConnectAction;
 import org.apache.plc4x.sandbox.java.s7.actions.InitContextAction;
 import org.apache.plc4x.sandbox.java.s7.actions.ReceiveAction;
 import org.apache.plc4x.sandbox.java.s7.actions.SendAction;
+import org.apache.plc4x.sandbox.java.s7.actions.s7.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() throws Exception {
+    private Poc(String stateMachineURI, String dataFormatURI) throws Exception {
+        this.dataFormatURI = dataFormatURI;
+
         // Initialize our PLC4X specific actions.
         List<CustomAction> customActions = new LinkedList<>();
         customActions.add(
@@ -49,10 +56,12 @@ public class Poc {
             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("org/apache/plc4x/protocols/s7/protocol.scxml.xml"),
+            Poc.class.getClassLoader().getResource(stateMachineURI),
             new SCXMLReader.Configuration(null, null, customActions));
 
         // Create an executor for running the state-machine.
@@ -62,12 +71,27 @@ public class Poc {
     }
 
     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();
+        executor.go(context);
     }
 
     public static void main(String[] args) throws Exception {
-        Poc poc = new Poc();
+        Poc poc = new Poc(
+            "org/apache/plc4x/protocols/s7/protocol.scxml.xml",
+            "org/apache/plc4x/protocols/s7/protocol.dfdl.xsd");
         poc.run();
     }
 
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java
new file mode 100644
index 0000000..cf37c81
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.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.s7.actions;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+
+import java.net.Socket;
+
+public abstract class BaseConnectedAction extends BasePlc4xAction {
+
+    public static final String SOCKET_PARAMETER_NAME="connection";
+
+    protected Socket getSocket(ActionExecutionContext ctx) {
+        return (Socket) ctx.getGlobalContext().get(SOCKET_PARAMETER_NAME);
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java
similarity index 74%
copy from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
copy to sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java
index e7bb675..4ed74ee 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java
@@ -20,32 +20,18 @@
 package org.apache.plc4x.sandbox.java.s7.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
-import org.apache.commons.scxml2.model.Action;
 import org.apache.commons.scxml2.model.ParsedValue;
 import org.apache.commons.scxml2.model.ParsedValueContainer;
 import org.apache.daffodil.japi.DataProcessor;
 import org.apache.daffodil.japi.Diagnostic;
 import org.apache.daffodil.japi.WithDiagnostics;
-import org.slf4j.Logger;
 
-import java.net.Socket;
 import java.util.List;
 
-public abstract class BasePlc4xAction extends Action implements ParsedValueContainer {
+public abstract class BaseDaffodilAction extends BaseConnectedAction implements ParsedValueContainer {
 
-
-
-    private String socketParameterName;
     private ParsedValue message;
 
-    public String getSocketParameterName() {
-        return socketParameterName;
-    }
-
-    public void setSocketParameterName(String socketParameterName) {
-        this.socketParameterName = socketParameterName;
-    }
-
     @Override
     public ParsedValue getParsedValue() {
         return message;
@@ -56,12 +42,6 @@ public abstract class BasePlc4xAction extends Action implements ParsedValueConta
         this.message = parsedValue;
     }
 
-    protected abstract Logger getLogger();
-
-    protected Socket getSocket(ActionExecutionContext ctx) {
-        return (Socket) ctx.getGlobalContext().get(getSocketParameterName());
-    }
-
     protected DataProcessor getDaffodilDataProcessor(ActionExecutionContext ctx) {
         return (DataProcessor) ctx.getGlobalContext().get("dfdl");
     }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
index e7bb675..6a763b6 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
@@ -20,57 +20,33 @@
 package org.apache.plc4x.sandbox.java.s7.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.Action;
-import org.apache.commons.scxml2.model.ParsedValue;
-import org.apache.commons.scxml2.model.ParsedValueContainer;
-import org.apache.daffodil.japi.DataProcessor;
-import org.apache.daffodil.japi.Diagnostic;
-import org.apache.daffodil.japi.WithDiagnostics;
 import org.slf4j.Logger;
 
-import java.net.Socket;
-import java.util.List;
-
-public abstract class BasePlc4xAction extends Action implements ParsedValueContainer {
-
-
-
-    private String socketParameterName;
-    private ParsedValue message;
-
-    public String getSocketParameterName() {
-        return socketParameterName;
-    }
-
-    public void setSocketParameterName(String socketParameterName) {
-        this.socketParameterName = socketParameterName;
-    }
-
-    @Override
-    public ParsedValue getParsedValue() {
-        return message;
-    }
-
-    @Override
-    public void setParsedValue(ParsedValue parsedValue) {
-        this.message = parsedValue;
-    }
+public abstract class BasePlc4xAction extends Action {
 
     protected abstract Logger getLogger();
 
-    protected Socket getSocket(ActionExecutionContext ctx) {
-        return (Socket) ctx.getGlobalContext().get(getSocketParameterName());
+    protected String getStateName() {
+        try {
+            return getParentEnterableState().getId();
+        } catch (Exception e) {
+            getLogger().error("Unable to get state.");
+        }
+        return "unknown";
     }
 
-    protected DataProcessor getDaffodilDataProcessor(ActionExecutionContext ctx) {
-        return (DataProcessor) ctx.getGlobalContext().get("dfdl");
+    protected void fireFailureEvent(ActionExecutionContext ctx, String message) {
+        TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
+            data(getStateName() + ": " + message).build();
+        ctx.getInternalIOProcessor().addEvent(event);
     }
 
-    protected void logDiagnosticInformation(WithDiagnostics withDiagnostics) {
-        List<Diagnostic> diags = withDiagnostics.getDiagnostics();
-        for (Diagnostic d : diags) {
-            getLogger().error(d.getSomeMessage());
-        }
+    protected void fireSuccessEvent(ActionExecutionContext ctx) {
+        TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).data(getStateName()).build();
+        ctx.getInternalIOProcessor().addEvent(event);
     }
 
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java
index 5a7a371..bf374d1 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java
@@ -20,14 +20,13 @@
 package org.apache.plc4x.sandbox.java.s7.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.Action;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.Socket;
 
-public class ConnectAction extends Action {
+public class ConnectAction extends BasePlc4xAction {
 
     private String type;
     private String host;
@@ -58,18 +57,24 @@ public class ConnectAction extends Action {
     }
 
     @Override
+    protected Logger getLogger() {
+        return LoggerFactory.getLogger(ConnectAction.class);
+    }
+
+    @Override
     public void execute(ActionExecutionContext ctx) {
-        ctx.getAppLog().info("Connecting...");
+        ctx.getAppLog().info(getStateName() + ": Connecting...");
         try {
             if ("TCP".equalsIgnoreCase(type)) {
                 Socket socket = new Socket(host, Integer.parseInt(port));
-                ctx.getGlobalContext().set("connection", socket);
-                TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
-                ctx.getInternalIOProcessor().addEvent(event);
+                ctx.getGlobalContext().set(BaseConnectedAction.SOCKET_PARAMETER_NAME, socket);
+
                 ctx.getAppLog().info("Connected.");
+
+                fireSuccessEvent(ctx);
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            getLogger().error("Error connecting to remote.", e);
         }
     }
 
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java
index 6b6e5f4..ed93053 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java
@@ -22,62 +22,67 @@ package org.apache.plc4x.sandbox.java.s7.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.Action;
 import org.apache.daffodil.japi.Compiler;
 import org.apache.daffodil.japi.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 
-public class InitContextAction extends Action {
+public class InitContextAction extends BasePlc4xAction {
 
-    private static final Logger logger = LoggerFactory.getLogger(InitContextAction.class);
+    private String protocolDaffodilSchemaName;
+
+    public String getProtocolDaffodilSchemaName() {
+        return protocolDaffodilSchemaName;
+    }
+
+    public void setProtocolDaffodilSchemaName(String protocolDaffodilSchemaName) {
+        this.protocolDaffodilSchemaName = protocolDaffodilSchemaName;
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return LoggerFactory.getLogger(InitContextAction.class);
+    }
 
     @Override
     public void execute(ActionExecutionContext ctx) {
-        ctx.getAppLog().info("Initializing Context.");
+        ctx.getAppLog().info(getStateName() + ": Initializing Context...");
 
         try {
             Compiler c = Daffodil.compiler();
             c.setValidateDFDLSchemas(true);
-            URL shemaUrl = SendAction.class.getClassLoader().getResource("org/apache/plc4x/protocols/s7/protocol.dfdl.xsd");
-            if (shemaUrl != null) {
-                URI schemaUri = shemaUrl.toURI();
+            String schemaUrlString = (String) ctx.getGlobalContext().get(protocolDaffodilSchemaName);
+            URL schemaUrl = SendAction.class.getClassLoader().getResource(schemaUrlString);
+            if (schemaUrl != null) {
+                URI schemaUri = schemaUrl.toURI();
                 ProcessorFactory pf = c.compileSource(schemaUri);
-                if (pf.isError()) {
-                    logDiagnosticInformation(pf);
-                    TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).build();
-                    ctx.getInternalIOProcessor().addEvent(event);
-                    return;
-                }
+                logDiagnosticInformation(pf);
                 DataProcessor dp = pf.onPath("/");
-                if (dp.isError()) {
-                    logDiagnosticInformation(dp);
-                    TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).build();
-                    ctx.getInternalIOProcessor().addEvent(event);
-                    return;
-                }
+                logDiagnosticInformation(dp);
                 ctx.getGlobalContext().set("dfdl", dp);
             }
-        } catch (IOException | URISyntaxException e) {
+        } catch (Exception e) {
+            fireFailureEvent(ctx, "Error initializing daffodil schema");
             TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).data(e).build();
             ctx.getInternalIOProcessor().addEvent(event);
             return;
         }
 
-        TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
-        ctx.getInternalIOProcessor().addEvent(event);
+        ctx.getAppLog().info("Context initialized.");
+        fireSuccessEvent(ctx);
     }
 
-    private void logDiagnosticInformation(WithDiagnostics withDiagnostics) {
-        List<Diagnostic> diags = withDiagnostics.getDiagnostics();
-        for (Diagnostic d : diags) {
-            logger.error(d.getSomeMessage());
+    private void logDiagnosticInformation(WithDiagnostics withDiagnostics) throws Exception {
+        if(withDiagnostics.isError()) {
+            List<Diagnostic> diags = withDiagnostics.getDiagnostics();
+            for (Diagnostic d : diags) {
+                getLogger().error(d.getSomeMessage());
+            }
+            throw new Exception();
         }
     }
 
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
index d17d937..39ab99f 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
@@ -27,27 +27,36 @@ 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.W3CDOMInfosetOutputter;
+import org.apache.daffodil.japi.infoset.JDOMInfosetOutputter;
+import org.apache.daffodil.japi.io.InputSourceDataInputStream;
+import org.jdom2.Document;
+import org.jdom2.Namespace;
+import org.jdom2.Text;
+import org.jdom2.filter.Filters;
+import org.jdom2.output.XMLOutputter;
+import org.jdom2.xpath.XPathExpression;
+import org.jdom2.xpath.XPathFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import java.io.BufferedReader;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.net.Socket;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
-public class ReceiveAction extends BasePlc4xAction {
+public class ReceiveAction extends BaseDaffodilAction {
 
-    private String timeout;
+    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;
@@ -62,19 +71,42 @@ public class ReceiveAction extends BasePlc4xAction {
         return LoggerFactory.getLogger(ReceiveAction.class);
     }
 
+    public String getPacketLengthStartPosition() {
+        return Integer.toString(packetLengthStartPosition);
+    }
+
+    public void setPacketLengthStartPosition(String packetLengthStartPosition) {
+        this.packetLengthStartPosition = Integer.valueOf(packetLengthStartPosition);
+    }
+
+    public String getPacketLengthSizeInBytes() {
+        return Integer.toString(packetLengthSizeInBytes);
+    }
+
+    public void setPacketLengthSizeInBytes(String packetLengthSizeInBytes) {
+        this.packetLengthSizeInBytes = Integer.valueOf(packetLengthSizeInBytes);
+    }
+
+    public String getPacketLengthOffset() {
+        return Integer.toString(packetLengthOffset);
+    }
+
+    public void setPacketLengthOffset(String packetLengthOffset) {
+        this.packetLengthOffset = Integer.valueOf(packetLengthOffset);
+    }
+
     public String getTimeout() {
-        return timeout;
+        return Long.toString(timeout);
     }
 
     public void setTimeout(String timeout) {
-        this.timeout = timeout;
+        this.timeout = Long.valueOf(timeout);
     }
 
     @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();
@@ -91,11 +123,11 @@ public class ReceiveAction extends BasePlc4xAction {
 
     private void parseElement(Element ruleElement) {
         String name = ruleElement.getAttribute("name");
-        String xpath = ruleElement.getAttribute("xpath");
-        if("verification".equals(ruleElement.getTagName())) {
-            verificationRules.put(name, xpath);
-        } else if("extraction".equals(ruleElement.getTagName())) {
-            extractionRules.put(name, xpath);
+        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());
         }
@@ -103,43 +135,132 @@ public class ReceiveAction extends BasePlc4xAction {
 
     @Override
     public void execute(ActionExecutionContext ctx) {
-        ctx.getAppLog().info("Receiving.");
+        ctx.getAppLog().info(getStateName() + ": Receiving...");
+
         try {
             DataProcessor dp = getDaffodilDataProcessor(ctx);
             if(dp == null) {
-                TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
-                    data("Couldn't initialize daffodil data processor.").build();
-                ctx.getInternalIOProcessor().addEvent(event);
+                fireFailureEvent(ctx, "Couldn't initialize daffodil data processor.");
                 return;
             }
 
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
             Socket connection = getSocket(ctx);
-            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
-            System.out.println(in.readLine());
+            DataInputStream inputStream = new DataInputStream(new BufferedInputStream(connection.getInputStream()));
+
+            // Remember when we started to receive.
+            long startTime = System.currentTimeMillis();
+
+            // Check if enough bytes are available to at least find out how big the full packet is.
+            while(inputStream.available() < packetLengthStartPosition + packetLengthSizeInBytes) {
+                waitWithTimeout(ctx, startTime, timeout);
+            }
+
+            // Read these length bytes and reset the input stream back to the start.
+            inputStream.mark(packetLengthStartPosition + packetLengthSizeInBytes);
+            // Jump to the start of the length data.
+            inputStream.skip(packetLengthStartPosition);
+
+            // Read the packet length.
+            int packetLength;
+            switch (packetLengthSizeInBytes) {
+                case 1:
+                    packetLength = inputStream.readUnsignedByte();
+                    break;
+                case 2:
+                    packetLength = inputStream.readUnsignedShort();
+                    break;
+                default:
+                    fireFailureEvent(ctx, "Unsupported size for packet length: " + packetLengthSizeInBytes);
+                    return;
+            }
+            packetLength += packetLengthOffset;
+
+            // Go back to the beginning of the packet.
+            inputStream.reset();
 
-            DataInputStream inputStream = new DataInputStream(connection.getInputStream());
-            ReadableByteChannel rbc = Channels.newChannel(inputStream);
-            W3CDOMInfosetOutputter outputter = new W3CDOMInfosetOutputter();
-            ParseResult byteMessage = dp.parse(rbc, outputter);
+            // Eventually wait till the entire packet is available.
+            while(inputStream.available() < packetLength) {
+                waitWithTimeout(ctx, startTime, timeout);
+            }
+
+            byte[] packet = new byte[packetLength];
+            if(inputStream.read(packet) != packetLength) {
+                TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
+                    data("Couldn't read entire packet.").build();
+                ctx.getInternalIOProcessor().addEvent(event);
+                return;
+            }
+
+            // After having enough bytes available, process the current package.
+            JDOMInfosetOutputter outputter = new JDOMInfosetOutputter();
+            ParseResult byteMessage = dp.parse(
+                new InputSourceDataInputStream(new ByteArrayInputStream(packet)), outputter);
             if (byteMessage.isError()) {
                 logDiagnosticInformation(byteMessage);
                 return;
             }
 
+            // Get the resulting XML document from the parser.
             Document message = outputter.getResult();
-            System.out.println(message);
-            ctx.getAppLog().info("Successfully sent message.");
+
+            // 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();
         }
 
-        TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
-        ctx.getInternalIOProcessor().addEvent(event);
+        ctx.getAppLog().info("Received.");
+        fireSuccessEvent(ctx);
+    }
+
+    private String getRuleText(Document message, String xpathExpression) {
+        // Get the namespace definitions from the input document.
+        List<Namespace> namespaces = message.getRootElement().getNamespacesInScope();
+
+        XPathFactory xPathFactory = XPathFactory.instance();
+        XPathExpression<org.jdom2.Text> xpath = xPathFactory.compile(
+            xpathExpression, Filters.textOnly(), null, namespaces);
+        List<Text> result = xpath.evaluate(message);
+        if((result == null) || result.isEmpty()) {
+            getLogger().info("Couldn't find value for xpath expression: " + xpathExpression + " in document.");
+            if(getLogger().isInfoEnabled()) {
+                getLogger().info(new XMLOutputter().outputString(message));
+            }
+            return null;
+        }
+        return result.get(0).getTextNormalize();
+    }
+
+    private void waitWithTimeout(ActionExecutionContext ctx, long startTime, long timeout) {
+        try {
+            TimeUnit.MILLISECONDS.sleep(20);
+            if(System.currentTimeMillis() - startTime > timeout) {
+                fireFailureEvent(ctx, "Receive timed out.");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
     }
 
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java
index f761ac3..bd4a467 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java
@@ -20,13 +20,11 @@
 package org.apache.plc4x.sandbox.java.s7.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.ParsedValue;
 import org.apache.daffodil.japi.DataProcessor;
 import org.apache.daffodil.japi.UnparseResult;
 import org.apache.daffodil.japi.infoset.InfosetInputter;
-import org.apache.daffodil.japi.infoset.W3CDOMInfosetInputter;
+import org.apache.plc4x.sandbox.java.s7.utils.W3CDOMTemplateInfosetInputter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -41,7 +39,7 @@ import java.net.Socket;
 import java.nio.channels.Channels;
 import java.nio.channels.WritableByteChannel;
 
-public class SendAction extends BasePlc4xAction {
+public class SendAction extends BaseDaffodilAction {
 
     @Override
     protected Logger getLogger() {
@@ -50,7 +48,8 @@ public class SendAction extends BasePlc4xAction {
 
     @Override
     public void execute(ActionExecutionContext ctx) {
-        ctx.getAppLog().info("Sending.");
+        ctx.getAppLog().info(getStateName() + ": Sending...");
+
         if(getParsedValue() != null) {
             if(getParsedValue().getType() == ParsedValue.ValueType.NODE) {
                 try {
@@ -63,12 +62,10 @@ public class SendAction extends BasePlc4xAction {
 
                     DataProcessor dp = getDaffodilDataProcessor(ctx);
                     if(dp == null) {
-                        TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
-                            data("Couldn't initialize daffodil data processor.").build();
-                        ctx.getInternalIOProcessor().addEvent(event);
+                        fireFailureEvent(ctx, "Couldn't initialize daffodil data processor.");
                         return;
                     }
-                    InfosetInputter inputter = new W3CDOMInfosetInputter(doc);
+                    InfosetInputter inputter = new W3CDOMTemplateInfosetInputter(doc, ctx.getGlobalContext());
 
                     Socket connection = getSocket(ctx);
                     DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
@@ -79,19 +76,17 @@ public class SendAction extends BasePlc4xAction {
                         return;
                     }
                     outputStream.flush();
-                    ctx.getAppLog().info("Successfully sent message.");
                 } catch(IOException | ParserConfigurationException e) {
                     e.printStackTrace();
                 }
             } else {
-                TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
-                    data("type '" + getParsedValue().getType() + "' not supported").build();
-                ctx.getInternalIOProcessor().addEvent(event);
+                fireFailureEvent(ctx, "type '" + getParsedValue().getType() + "' not supported");
                 return;
             }
         }
-        TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
-        ctx.getInternalIOProcessor().addEvent(event);
+
+        ctx.getAppLog().info("Sent.");
+        fireSuccessEvent(ctx);
     }
 
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/s7/S7DecodeArticleNumber.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/s7/S7DecodeArticleNumber.java
new file mode 100644
index 0000000..46e897b
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/s7/S7DecodeArticleNumber.java
@@ -0,0 +1,91 @@
+/*
+ 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.s7.actions.s7;
+
+import org.apache.commons.scxml2.ActionExecutionContext;
+import org.apache.commons.scxml2.model.ActionExecutionError;
+import org.apache.plc4x.sandbox.java.s7.actions.BasePlc4xAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class S7DecodeArticleNumber extends BasePlc4xAction {
+
+    private String articleNumberParameterName;
+    private String plcTypeParameterName;
+
+    public String getArticleNumberParameterName() {
+        return articleNumberParameterName;
+    }
+
+    public void setArticleNumberParameterName(String articleNumberParameterName) {
+        this.articleNumberParameterName = articleNumberParameterName;
+    }
+
+    public String getPlcTypeParameterName() {
+        return plcTypeParameterName;
+    }
+
+    public void setPlcTypeParameterName(String plcTypeParameterName) {
+        this.plcTypeParameterName = plcTypeParameterName;
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return LoggerFactory.getLogger(S7DecodeArticleNumber.class);
+    }
+
+    @Override
+    public void execute(ActionExecutionContext ctx) throws ActionExecutionError {
+        String articleNumber = ctx.getGlobalContext().get(articleNumberParameterName).toString();
+        if(articleNumber == null) {
+            fireFailureEvent(ctx, "Couldn't find article number.");
+            return;
+        }
+
+        String plcType = lookupControllerType(articleNumber);
+        if(plcType == null) {
+            fireFailureEvent(ctx, "Unknown PLC type for article number: " + articleNumber);
+        }
+
+        ctx.getGlobalContext().set(plcTypeParameterName, plcType);
+        fireSuccessEvent(ctx);
+    }
+
+    private String lookupControllerType(String articleNumber) {
+        if(!articleNumber.startsWith("6ES7 ")) {
+            return null;
+        }
+
+        String model = articleNumber.substring(articleNumber.indexOf(' ') + 1, articleNumber.indexOf(' ') + 2);
+        switch (model) {
+            case "2":
+                return "S7-1200";
+            case "5":
+                return "S7-1500";
+            case "3":
+                return "S7-300";
+            case "4":
+                return "S7-400";
+            default:
+                return null;
+        }
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala b/sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala
new file mode 100644
index 0000000..04a83fd
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala
@@ -0,0 +1,42 @@
+/*
+ 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.s7.utils
+
+import org.apache.commons.scxml2.Context
+import org.apache.daffodil.dpath.NodeInfo
+import org.apache.daffodil.japi.infoset.{InfosetInputterProxy, W3CDOMInfosetInputter}
+
+class W3CDOMTemplateInfosetInputter(document: org.w3c.dom.Document, context: Context) extends InfosetInputterProxy {
+
+    override val infosetInputter = new W3CDOMInfosetInputter(document)
+
+    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
+            }
+        }
+        value
+    }
+
+}


[incubator-plc4x] 02/02: - Continued working on the dynamic s7 driver

Posted by cd...@apache.org.
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

commit 6c49277e0af21ca24f803c14685d78f417244cdd
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Feb 7 22:30:00 2019 +0100

    - Continued working on the dynamic s7 driver
    
    (It's current state allows connecting to S7 devices, however no read/write/subscription functionality is enabled)
---
 .../apache/plc4x/protocols/s7/protocol.scxml.xml   |  17 ++-
 .../pom.xml                                        |  25 ++-
 .../java/dynamic}/actions/BaseConnectedAction.java |   2 +-
 .../java/dynamic}/actions/BaseDaffodilAction.java  |   2 +-
 .../java/dynamic}/actions/BasePlc4xAction.java     |   2 +-
 .../java/dynamic}/actions/ConnectAction.java       |   2 +-
 .../java/dynamic}/actions/InitContextAction.java   |   2 +-
 .../java/dynamic}/actions/ReceiveAction.java       |   2 +-
 .../sandbox/java/dynamic}/actions/SendAction.java  |   4 +-
 .../connection/DynamicDriverConnectionBase.java    | 134 +++++++++++++++++
 .../utils/W3CDOMTemplateInfosetInputter.scala      |   2 +-
 sandbox/dynamic-driver-s7/pom.xml                  |  36 ++---
 .../sandbox/java/dynamic/s7/DynamicS7Driver.java   |  77 ++++++++++
 .../plc4x/sandbox/java/{ => dynamic}/s7/Poc.java   |  20 ++-
 .../s7/actions}/S7DecodeArticleNumber.java         |   4 +-
 .../dynamic/s7/connection/DynamicS7Connection.java | 167 +++++++++++++++++++++
 .../s7/utils/S7TsapIdEncoder.java}                 |  25 ++-
 .../services/org.apache.plc4x.java.spi.PlcDriver   |  38 +++++
 sandbox/pom.xml                                    |   1 +
 19 files changed, 492 insertions(+), 70 deletions(-)

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 bfab15c..eba7511 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
@@ -68,6 +68,7 @@
       </sc:onentry>
       <sc:transition event="success" target="sendCotpConnectionRequest"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -126,6 +127,7 @@
       </sc:onentry>
       <sc:transition event="success" target="receiveCotpConnectionResponse"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -145,6 +147,7 @@
       </sc:onentry>
       <sc:transition event="success" target="sendS7SetupCommunicationRequest"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -198,6 +201,7 @@
       </sc:onentry>
       <sc:transition event="success" target="receiveS7SetupCommunicationResponse"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -222,6 +226,7 @@
       <sc:transition event="success" cond="plcType == null" target="sendS7IdentificationRequest"/>
       <sc:transition event="success" cond="plcType != null" target="connected"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -284,6 +289,7 @@
       </sc:onentry>
       <sc:transition event="success" target="receiveS7IdentificationRequest"/>
       <sc:transition event="failure" target="error"/>
+      <sc:transition event="disconnect" target="disconnect"/>
     </sc:state>
 
     <!--
@@ -304,7 +310,8 @@
         <plc4x:S7DecodeArticleNumber articleNumberParameterName="s7ArticleNumber" plcTypeParameterName="plcType"/>
       </sc:transition>
       <sc:transition event="failure" target="error"/>
-    </sc:state>
+      <sc:transition event="disconnect" target="disconnect"/>
+   </sc:state>
 
     <!--
       Default state after connecting to a PLC.
@@ -313,6 +320,14 @@
       <sc:onentry>
         <sc:log expr="'Connected to PLC of type: ' + plcType"/>
       </sc:onentry>
+      <sc:transition event="disconnect" target="disconnect"/>
+    </sc:state>
+
+    <!--
+      Initiate disconnecting.
+    -->
+    <sc:state id="disconnect">
+      <sc:transition event="disconnect" target="disconnected"/>
     </sc:state>
 
     <!--
diff --git a/sandbox/dynamic-driver-s7/pom.xml b/sandbox/dynamic-driver-base/pom.xml
similarity index 86%
copy from sandbox/dynamic-driver-s7/pom.xml
copy to sandbox/dynamic-driver-base/pom.xml
index f302333..8b0c9d0 100644
--- a/sandbox/dynamic-driver-s7/pom.xml
+++ b/sandbox/dynamic-driver-base/pom.xml
@@ -27,12 +27,18 @@
     <version>0.4.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>plc4j-dynamic-driver-s7</artifactId>
-  <name>Sandbox: Dynamic-Driver: S7</name>
-  <description>Implementation of a S7 driver based on definitions provided by DFDL and SCXML.</description>
+  <artifactId>plc4j-dynamic-driver-base</artifactId>
+  <name>Sandbox: Dynamic-Driver: (Base)</name>
+  <description>Base Implementation of a driver based on definitions provided by DFDL and SCXML.</description>
 
   <dependencies>
     <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-scxml2</artifactId>
       <version>2.0-SNAPSHOT</version>
@@ -63,17 +69,6 @@
       <artifactId>jaxen</artifactId>
       <version>1.1.6</version>
     </dependency>
-
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-simple</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.plc4x</groupId>
-      <artifactId>plc4x-protocols-s7</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
-      <scope>runtime</scope>
-    </dependency>
   </dependencies>
 
   <build>
@@ -110,9 +105,7 @@
         <artifactId>maven-dependency-plugin</artifactId>
         <configuration>
           <usedDependencies combine.children="append">
-            <usedDependency>org.apache.plc4x:plc4x-protocols-s7</usedDependency>
             <usedDependency>org.apache.commons:commons-jexl3</usedDependency>
-            <usedDependency>org.slf4j:slf4j-simple</usedDependency>
           </usedDependencies>
         </configuration>
       </plugin>
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseConnectedAction.java
similarity index 95%
copy from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java
copy to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseConnectedAction.java
index cf37c81..bdc3cc5 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseConnectedAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseDaffodilAction.java
similarity index 97%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseDaffodilAction.java
index 4ed74ee..b3ef163 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseDaffodilAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BaseDaffodilAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.model.ParsedValue;
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
similarity index 97%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
index 6a763b6..3693294 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/BasePlc4xAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.EventBuilder;
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ConnectAction.java
similarity index 97%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ConnectAction.java
index bf374d1..e5df22e 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ConnectAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ConnectAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.slf4j.Logger;
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
similarity index 98%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
index ed93053..bbc3b5d 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/InitContextAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/InitContextAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.EventBuilder;
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
similarity index 99%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
index 39ab99f..4db3fd9 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/ReceiveAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/ReceiveAction.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.EventBuilder;
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
similarity index 96%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java
rename to sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
index bd4a467..6421cf6 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/SendAction.java
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/actions/SendAction.java
@@ -17,14 +17,14 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+package org.apache.plc4x.sandbox.java.dynamic.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 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.s7.utils.W3CDOMTemplateInfosetInputter;
+import org.apache.plc4x.sandbox.java.dynamic.utils.W3CDOMTemplateInfosetInputter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
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
new file mode 100644
index 0000000..d27510d
--- /dev/null
+++ b/sandbox/dynamic-driver-base/src/main/java/org/apache/plc4x/sandbox/java/dynamic/connection/DynamicDriverConnectionBase.java
@@ -0,0 +1,134 @@
+/*
+ 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.connection;
+
+import org.apache.commons.scxml2.EventBuilder;
+import org.apache.commons.scxml2.SCXMLExecutor;
+import org.apache.commons.scxml2.TriggerEvent;
+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.ModelException;
+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 javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.util.*;
+
+public abstract class DynamicDriverConnectionBase implements PlcConnection {
+
+    private String stateMachineURI;
+    private String dataFormatURI;
+    private SCXMLExecutor executor;
+
+    protected DynamicDriverConnectionBase(String stateMachineURI, String dataFormatURI) {
+        this.stateMachineURI = stateMachineURI;
+        this.dataFormatURI = dataFormatURI;
+    }
+
+    private void init() throws PlcConnectionException {
+        // 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.addAll(getAdditionalCustomActions());
+
+        try {
+            // Initialize the state-machine with the definition from the protocol module.
+            SCXML scxml = SCXMLReader.read(
+                DynamicDriverConnectionBase.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);
+        } catch (XMLStreamException | IOException | ModelException e) {
+            throw new PlcConnectionException("Error initializing driver state-machine", e);
+        }
+    }
+
+    protected Collection<CustomAction> getAdditionalCustomActions() {
+        return Collections.emptyList();
+    }
+
+    protected Map<String, Object> getAdditionalContextDataItems() {
+        return Collections.emptyMap();
+    }
+
+    protected abstract String getConnectedStateName();
+
+    protected abstract String getDisconnectTransitionName();
+
+    @Override
+    public void connect() throws PlcConnectionException {
+        // Setup the driver.
+        init();
+
+        // Initialize the drivers state.
+        Map<String, Object> context = new HashMap<>();
+        context.put("protocolDaffodilSchema", dataFormatURI);
+        getAdditionalContextDataItems().forEach(context::put);
+
+        try {
+            // Run the state-machine.
+            executor.go(context);
+        } catch (ModelException e) {
+            throw new PlcConnectionException("Error initializing driver state-machine", e);
+        }
+    }
+
+    @Override
+    public boolean isConnected() {
+        if(executor == null) {
+            return false;
+        }
+        return executor.getStatus().isInState(getConnectedStateName());
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(executor == null) {
+            return;
+        }
+        executor.triggerEvent(new EventBuilder(getDisconnectTransitionName(), TriggerEvent.SIGNAL_EVENT).build());
+    }
+
+    @Override
+    public PlcConnectionMetadata getMetadata() {
+        return null;
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala b/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
similarity index 96%
rename from sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala
rename to sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
index 04a83fd..d2c517f 100644
--- a/sandbox/dynamic-driver-s7/src/main/scala/org/apache/plc4x/sandbox/java/s7/utils/W3CDOMTemplateInfosetInputter.scala
+++ b/sandbox/dynamic-driver-base/src/main/scala/org/apache/plc4x/sandbox/java/dynamic/utils/W3CDOMTemplateInfosetInputter.scala
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.utils
+package org.apache.plc4x.sandbox.java.dynamic.utils
 
 import org.apache.commons.scxml2.Context
 import org.apache.daffodil.dpath.NodeInfo
diff --git a/sandbox/dynamic-driver-s7/pom.xml b/sandbox/dynamic-driver-s7/pom.xml
index f302333..06dd27d 100644
--- a/sandbox/dynamic-driver-s7/pom.xml
+++ b/sandbox/dynamic-driver-s7/pom.xml
@@ -33,6 +33,11 @@
 
   <dependencies>
     <dependency>
+      <groupId>org.apache.plc4x.sandbox</groupId>
+      <artifactId>plc4j-dynamic-driver-base</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-scxml2</artifactId>
       <version>2.0-SNAPSHOT</version>
@@ -47,6 +52,10 @@
       <artifactId>commons-jexl3</artifactId>
       <version>3.1</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>commons-logging</groupId>
@@ -79,33 +88,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>net.alchim31.maven</groupId>
-        <artifactId>scala-maven-plugin</artifactId>
-        <version>3.4.6</version>
-        <executions>
-          <execution>
-            <id>add-scala-sources</id>
-            <phase>validate</phase>
-            <goals>
-              <goal>add-source</goal>
-            </goals>
-            <configuration>
-              <sourceDir>src/main/scala</sourceDir>
-            </configuration>
-          </execution>
-          <execution>
-            <id>compile-scala</id>
-            <phase>compile</phase>
-            <goals>
-              <goal>compile</goal>
-            </goals>
-            <configuration>
-              <outputDir>${project.build.outputDirectory}</outputDir>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <configuration>
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
new file mode 100644
index 0000000..a5b1eb5
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/DynamicS7Driver.java
@@ -0,0 +1,77 @@
+/*
+ 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.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.authentication.PlcAuthentication;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.spi.PlcDriver;
+import org.apache.plc4x.sandbox.java.dynamic.s7.connection.DynamicS7Connection;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DynamicS7Driver implements PlcDriver {
+
+    private static final Pattern S7_URI_PATTERN = Pattern.compile("^s7d://(?<host>.*)/(?<rack>\\d{1,4})/(?<slot>\\d{1,4})(?<params>\\?.*)?");
+
+    @Override
+    public String getProtocolCode() {
+        return "s7d";
+    }
+
+    @Override
+    public String getProtocolName() {
+        return "Siemens S7 (Basic - Dynamic)";
+    }
+
+    @Override
+    public PlcConnection connect(String url) throws PlcConnectionException {
+        Matcher matcher = S7_URI_PATTERN.matcher(url);
+        if (!matcher.matches()) {
+            throw new PlcConnectionException(
+                "Connection url doesn't match the format 's7://{host|ip}/{rack}/{slot}'");
+        }
+        String host = matcher.group("host");
+
+        int rack = Integer.parseInt(matcher.group("rack"));
+        int slot = Integer.parseInt(matcher.group("slot"));
+        String params = matcher.group("params") != null ? matcher.group("params").substring(1) : null;
+
+        try {
+            InetAddress serverInetAddress = InetAddress.getByName(host);
+            DynamicS7Connection connection = new DynamicS7Connection(serverInetAddress, rack, slot, params);
+            connection.connect();
+            return connection;
+        } catch (UnknownHostException e) {
+            throw new PlcConnectionException("Error parsing address", e);
+        } catch (Exception e) {
+            throw new PlcConnectionException("Error connecting to host", e);
+        }
+    }
+
+    @Override
+    public PlcConnection connect(String url, PlcAuthentication authentication) throws PlcConnectionException {
+        throw new PlcConnectionException("Basic S7 connections don't support authentication.");
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java
similarity index 85%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java
rename to sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java
index 04faee4..fe3d771 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/Poc.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/Poc.java
@@ -17,7 +17,7 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7;
+package org.apache.plc4x.sandbox.java.dynamic.s7;
 
 import org.apache.commons.scxml2.SCXMLExecutor;
 import org.apache.commons.scxml2.env.SimpleDispatcher;
@@ -26,11 +26,12 @@ 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.sandbox.java.s7.actions.ConnectAction;
-import org.apache.plc4x.sandbox.java.s7.actions.InitContextAction;
-import org.apache.plc4x.sandbox.java.s7.actions.ReceiveAction;
-import org.apache.plc4x.sandbox.java.s7.actions.SendAction;
-import org.apache.plc4x.sandbox.java.s7.actions.s7.S7DecodeArticleNumber;
+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;
@@ -89,10 +90,13 @@ public class Poc {
     }
 
     public static void main(String[] args) throws Exception {
-        Poc poc = new Poc(
+        /*Poc poc = new Poc(
             "org/apache/plc4x/protocols/s7/protocol.scxml.xml",
             "org/apache/plc4x/protocols/s7/protocol.dfdl.xsd");
-        poc.run();
+        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/s7/actions/s7/S7DecodeArticleNumber.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeArticleNumber.java
similarity index 95%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/s7/S7DecodeArticleNumber.java
rename to sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeArticleNumber.java
index 46e897b..8ced6eb 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/s7/S7DecodeArticleNumber.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/actions/S7DecodeArticleNumber.java
@@ -17,11 +17,11 @@
  under the License.
  */
 
-package org.apache.plc4x.sandbox.java.s7.actions.s7;
+package org.apache.plc4x.sandbox.java.dynamic.s7.actions;
 
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.model.ActionExecutionError;
-import org.apache.plc4x.sandbox.java.s7.actions.BasePlc4xAction;
+import org.apache.plc4x.sandbox.java.dynamic.actions.BasePlc4xAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
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
new file mode 100644
index 0000000..a70564a
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/connection/DynamicS7Connection.java
@@ -0,0 +1,167 @@
+/*
+ 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.connection;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.scxml2.model.CustomAction;
+import org.apache.plc4x.java.api.exceptions.PlcUnsupportedOperationException;
+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.sandbox.java.dynamic.connection.DynamicDriverConnectionBase;
+import org.apache.plc4x.sandbox.java.dynamic.s7.actions.S7DecodeArticleNumber;
+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.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DynamicS7Connection extends DynamicDriverConnectionBase {
+
+    private static final Logger logger = LoggerFactory.getLogger(DynamicS7Connection.class);
+
+    private final InetAddress address;
+    private final short calledTsapId;
+    private final short callingTsapId;
+
+    private short paramPduSize;
+    private short paramMaxAmqCaller;
+    private short paramMaxAmqCallee;
+    private String paramControllerType;
+
+    public DynamicS7Connection(InetAddress address, int rack, int slot, String params) {
+        super("org/apache/plc4x/protocols/s7/protocol.scxml.xml",
+            "org/apache/plc4x/protocols/s7/protocol.dfdl.xsd");
+
+        this.address = address;
+        this.calledTsapId = S7TsapIdEncoder.encodeS7TsapId((byte) 0x02, 0, 0);
+        this.callingTsapId = S7TsapIdEncoder.encodeS7TsapId((byte) 0x01, rack, slot);
+
+        short curParamPduSize = 1024;
+        short curParamMaxAmqCaller = 8;
+        short curParamMaxAmqCallee = 8;
+        String curParamControllerType = null;
+
+        if (!StringUtils.isEmpty(params)) {
+            for (String param : params.split("&")) {
+                String[] paramElements = param.split("=");
+                String paramName = paramElements[0];
+                if (paramElements.length == 2) {
+                    String paramValue = paramElements[1];
+                    switch (paramName) {
+                        case "pdu-size":
+                            curParamPduSize = Short.parseShort(paramValue);
+                            break;
+                        case "max-amq-caller":
+                            curParamMaxAmqCaller = Short.parseShort(paramValue);
+                            break;
+                        case "max-amq-callee":
+                            curParamMaxAmqCallee = Short.parseShort(paramValue);
+                            break;
+                        case "controller-type":
+                            curParamControllerType = paramValue;
+                            break;
+                        default:
+                            logger.debug("Unknown parameter {} with value {}", paramName, paramValue);
+                    }
+                } else {
+                    logger.debug("Unknown no-value parameter {}", paramName);
+                }
+            }
+        }
+
+        // It seems that the LOGO devices are a little picky about the pdu-size.
+        // Instead of handling this out, they just hang up without any error message.
+        // So in case of a LOGO controller, set this to a known working value.
+        if((curParamControllerType != null) && curParamControllerType.equalsIgnoreCase("logo") && curParamPduSize == 1024) {
+            curParamPduSize = 480;
+        }
+
+        // IsoTP uses pre defined sizes. Find the smallest box,
+        // that would be able to contain the requested pdu size.
+        this.paramPduSize = curParamPduSize;
+        this.paramMaxAmqCaller = curParamMaxAmqCaller;
+        this.paramMaxAmqCallee = curParamMaxAmqCallee;
+        this.paramControllerType = curParamControllerType;
+    }
+
+    @Override
+    protected String getConnectedStateName() {
+        return "connected";
+    }
+
+    @Override
+    protected String getDisconnectTransitionName() {
+        return "disconnect";
+    }
+
+    @Override
+    protected Collection<CustomAction> getAdditionalCustomActions() {
+        return Collections.singleton(
+            new CustomAction("https://plc4x.apache.org/scxml-extension", "S7DecodeArticleNumber",
+                S7DecodeArticleNumber.class));
+    }
+
+    @Override
+    protected Map<String, Object> getAdditionalContextDataItems() {
+        Map<String, Object> dataItems = new HashMap<>();
+
+        dataItems.put("hostname", address.getHostAddress());
+        dataItems.put("port", "102");
+        dataItems.put("plcType", paramControllerType);
+
+        dataItems.put("cotpLocalReference", "15");
+        dataItems.put("cotpCalledTsap", Short.toString(calledTsapId));
+        dataItems.put("cotpCallingTsap", Short.toString(callingTsapId));
+        dataItems.put("cotpTpduSize", "10");
+
+        dataItems.put("s7PduLength", Short.toString(paramPduSize));
+        dataItems.put("s7MaxAmqCaller", Short.toString(paramMaxAmqCaller));
+        dataItems.put("s7MaxAmqCallee", Short.toString(paramMaxAmqCallee));
+
+        return dataItems;
+    }
+
+    @Override
+    public PlcReadRequest.Builder readRequestBuilder() {
+        throw new PlcUnsupportedOperationException("The connection does not support reading");
+    }
+
+    @Override
+    public PlcWriteRequest.Builder writeRequestBuilder() {
+        throw new PlcUnsupportedOperationException("The connection does not support writing");
+    }
+
+    @Override
+    public PlcSubscriptionRequest.Builder subscriptionRequestBuilder() {
+        throw new PlcUnsupportedOperationException("The connection does not support subscription");
+    }
+
+    @Override
+    public PlcUnsubscriptionRequest.Builder unsubscriptionRequestBuilder() {
+        throw new PlcUnsupportedOperationException("The connection does not support subscription");
+    }
+
+}
diff --git a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7TsapIdEncoder.java
similarity index 52%
rename from sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java
rename to sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7TsapIdEncoder.java
index cf37c81..9e87c51 100644
--- a/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BaseConnectedAction.java
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/dynamic/s7/utils/S7TsapIdEncoder.java
@@ -16,19 +16,30 @@
  specific language governing permissions and limitations
  under the License.
  */
+package org.apache.plc4x.sandbox.java.dynamic.s7.utils;
 
-package org.apache.plc4x.sandbox.java.s7.actions;
+public class S7TsapIdEncoder {
 
-import org.apache.commons.scxml2.ActionExecutionContext;
+    private S7TsapIdEncoder() {
+        // Prevent this from being instantiated.
+    }
 
-import java.net.Socket;
+    public static short encodeS7TsapId(byte deviceGroup, int rack, int slot) {
+        short firstByte = (short) (deviceGroup << 8);
+        short secondByte = (short) ((rack << 4) | (slot & 0x0F));
+        return (short) (firstByte | secondByte);
+    }
 
-public abstract class BaseConnectedAction extends BasePlc4xAction {
+    public static byte decodeDeviceGroup(short tsapId) {
+        return (byte) ((tsapId >> 8) & (0xFF));
+    }
 
-    public static final String SOCKET_PARAMETER_NAME="connection";
+    public static int decodeRack(short tsapId) {
+        return (tsapId >> 4) & 0xF;
+    }
 
-    protected Socket getSocket(ActionExecutionContext ctx) {
-        return (Socket) ctx.getGlobalContext().get(SOCKET_PARAMETER_NAME);
+    public static int decodeSlot(short tsapId) {
+        return tsapId & 0xF;
     }
 
 }
diff --git a/sandbox/dynamic-driver-s7/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/dynamic-driver-s7/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
new file mode 100644
index 0000000..8609dd7
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+#
+# 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.
+#
+org.apache.plc4x.sandbox.java.dynamic.s7.DynamicS7Driver
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index f5301bf..bf2effd 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -35,6 +35,7 @@
   <description>Place where new stuff is located before it is regarded production-quality.</description>
 
   <modules>
+    <module>dynamic-driver-base</module>
     <module>dynamic-driver-s7</module>
   </modules>