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/06 10:20:35 UTC

[incubator-plc4x] branch develop updated: - Fixed a bug in the SCXML template making the S7 not respond correctly - Started implementing the processing of responses in SCXML

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new f0e7d31  - Fixed a bug in the SCXML template making the S7 not respond correctly - Started implementing the processing of responses in SCXML
f0e7d31 is described below

commit f0e7d31d8ed0ef14cebe557485337078795fb132
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Feb 6 11:20:25 2019 +0100

    - Fixed a bug in the SCXML template making the S7 not respond correctly
    - Started implementing the processing of responses in SCXML
---
 pom.xml                                            |   5 +
 .../apache/plc4x/protocols/s7/protocol.scxml.xml   | 206 ++++++---------------
 sandbox/dynamic-driver-s7/pom.xml                  |   4 +
 .../java/org/apache/plc4x/sandbox/java/s7/Poc.java |  10 +-
 .../sandbox/java/s7/actions/BasePlc4xAction.java   |  76 ++++++++
 .../sandbox/java/s7/actions/ConnectAction.java     |   7 +-
 .../sandbox/java/s7/actions/InitContextAction.java |  48 +++++
 .../sandbox/java/s7/actions/ReceiveAction.java     | 103 ++++++++++-
 .../plc4x/sandbox/java/s7/actions/SendAction.java  |  98 ++++------
 9 files changed, 339 insertions(+), 218 deletions(-)

diff --git a/pom.xml b/pom.xml
index ac58c96..e83282c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -582,6 +582,11 @@
         <version>${slf4j.version}</version>
       </dependency>
       <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-simple</artifactId>
+        <version>${slf4j.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.spockframework</groupId>
         <artifactId>spock-core</artifactId>
         <version>${spock.version}</version>
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 7f07b76..e272f77 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
@@ -27,7 +27,6 @@
 
   <sc:datamodel>
     <sc:data id="args"/>
-    <sc:data id="connection"/>
   </sc:datamodel>
 
   <sc:state id="init">
@@ -50,15 +49,13 @@
         <!-- Initialize the network connection to the remote host using the tcp adapter with a given host and port -->
         <plc4x:connect type="tcp" host="10.10.64.20" port="102"/>
       </sc:onentry>
-      <sc:transition event="success" target="sendCotpConnectionRequest">
-        <sc:assign location="connection" expr="_event.data"/>
-      </sc:transition>
+      <sc:transition event="success" target="sendCotpConnectionRequest"/>
       <sc:transition event="failure" target="error"/>
     </sc:state>
 
     <sc:state id="sendCotpConnectionRequest">
       <sc:onentry>
-        <plc4x:send socket="connection">
+        <plc4x:send socketParameterName="connection">
           <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
@@ -69,24 +66,24 @@
               <s7:CotpTpduConnectionRequest>
                 <destinationReference>0</destinationReference>
                 <!-- Insert the value for "cotp-local-reference" as short here -->
-                <sourceReference>16</sourceReference><!--plc4x:insert type="s7:short" name="cotp-local-reference"/-->
+                <sourceReference>15</sourceReference><!--plc4x:insert type="s7:short" name="cotp-local-reference"/-->
                 <protocolClass>0</protocolClass>
                 <s7:parameters>
                   <parameter>
-                    <type>193</type>
-                    <parameterLength>2</parameterLength>
-                    <s7:CotpParameterCallingTsap>
-                      <tsapId>256</tsapId><!--plc4x:insert type="s7:short" name="cotp-calling-tsap"/-->
-                    </s7:CotpParameterCallingTsap>
-                  </parameter>
-                  <parameter>
                     <type>194</type>
                     <parameterLength>2</parameterLength>
                     <s7:CotpParameterCalledTsap>
-                      <tsapId>258</tsapId><!--plc4x:insert type="s7:short" name="cotp-called-tsap"/-->
+                      <tsapId>512</tsapId><!--plc4x:insert type="s7:short" name="cotp-called-tsap"/-->
                     </s7:CotpParameterCalledTsap>
                   </parameter>
                   <parameter>
+                    <type>193</type>
+                    <parameterLength>2</parameterLength>
+                    <s7:CotpParameterCallingTsap>
+                      <tsapId>273</tsapId><!--plc4x:insert type="s7:short" name="cotp-calling-tsap"/-->
+                    </s7:CotpParameterCallingTsap>
+                  </parameter>
+                  <parameter>
                     <type>192</type>
                     <parameterLength>1</parameterLength>
                     <s7:CotpParameterTpduSize>
@@ -105,56 +102,12 @@
 
     <sc:state id="receiveCotpConnectionResponse">
       <sc:onentry>
-        <plc4x:receive timeout="5000">
-          <s7:tpktMessage>
-            <magicByte>3</magicByte>
-            <reserved>0</reserved>
-            <!-- Just ignore the content of this field, we don't care about it as it's only required for parsing. -->
-            <length><plc4x:ignore/></length>
-            <userData>
-              <!-- Just ignore the content of this field, we don't care about it as it's only required for parsing. -->
-              <headerLength><plc4x:ignore/></headerLength>
-              <type>208</type>
-              <CotpTpduConnectionResponse>
-                <!-- Make sure the reply uses the same reference as we used in the request. -->
-                <destinationReference><plc4x:verify type="s7:short" name="cotp-local-reference"/></destinationReference>
-                <!-- Extract the reference the remote would like us to use in this session. -->
-                <sourceReference><plc4x:extract type="s7:short" name="cotp-remote-reference"/></sourceReference>
-                <protocolClass>0</protocolClass>
-                <parameters>
-                  <!--
-                    These elements might be transferred in alternate order, we just care about all of them being
-                    transferred.
-                  -->
-                  <plc4x:unordered>
-                    <parameter>
-                      <type>192</type>
-                      <parameterLength>1</parameterLength>
-                      <CotpParameterTpduSize>
-                        <tpduSize><plc4x:extract type="s7:byte" name="cotp-tpdu-size"/></tpduSize>
-                      </CotpParameterTpduSize>
-                    </parameter>
-                    <parameter>
-                      <type>193</type>
-                      <parameterLength>2</parameterLength>
-                      <CotpParameterCallingTsap>
-                        <tsapId><plc4x:extract type="s7:short" name="cotp-calling-tsap"/></tsapId>
-                      </CotpParameterCallingTsap>
-                    </parameter>
-                    <parameter>
-                      <type>194</type>
-                      <parameterLength>2</parameterLength>
-                      <CotpParameterCalledTsap>
-                        <tsapId><plc4x:extract type="s7:short" name="cotp-called-tsap"/></tsapId>
-                      </CotpParameterCalledTsap>
-                    </parameter>
-                    <!-- The remote might be passing other parameters, we'll just ignore them for now -->
-                    <plc4x:ignore/>
-                  </plc4x:unordered>
-                </parameters>
-              </CotpTpduConnectionResponse>
-            </userData>
-          </s7:tpktMessage>
+        <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>
       </sc:onentry>
       <sc:transition event="success" target="sendS7SetupCommunicationRequest"/>
@@ -163,46 +116,46 @@
 
     <sc:state id="sendS7SetupCommunicationRequest">
       <sc:onentry>
-        <plc4x:send>
-          <s7:tpktMessage>
+        <plc4x:send socketParameterName="connection">
+          <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
             <length>25</length>
             <userData>
               <headerLength>2</headerLength>
               <type>240</type>
-              <CotpTpduData>
+              <s7:CotpTpduData>
                 <endOfTransmission>1</endOfTransmission>
                 <tpduRef>0</tpduRef>
-              </CotpTpduData>
+              </s7:CotpTpduData>
               <userData>
                 <magicByte>50</magicByte>
                 <type>1</type>
-                <S7RequestMessage>
+                <s7:S7RequestMessage>
                   <reserved>0</reserved>
                   <tpduReference>0</tpduReference>
                   <parametersLength>8</parametersLength>
                   <payloadsLength>0</payloadsLength>
-                  <parameters>
+                  <s7:parameters>
                     <parameter>
                       <type>240</type>
-                      <S7GeneralParameterSetupCommunication>
+                      <s7:S7GeneralParameterSetupCommunication>
                         <reserved>0</reserved>
-                        <maxAmqCaller><plc4x:insert type="s7:short" name="s7-max-amq-caller"/></maxAmqCaller>
-                        <maxAmqCallee><plc4x:insert type="s7:short" name="s7-max-amq-callee"/></maxAmqCallee>
-                        <pduLength><plc4x:insert type="s7:short" name="s7-pdu-length"/></pduLength>
-                      </S7GeneralParameterSetupCommunication>
+                        <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"/-->
+                      </s7:S7GeneralParameterSetupCommunication>
                     </parameter>
-                  </parameters>
+                  </s7:parameters>
                   <payloads>
                     <payload>
-                      <S7GeneralPayloadSetupCommunication/>
+                      <s7:S7GeneralPayloadSetupCommunication/>
                     </payload>
                   </payloads>
-                </S7RequestMessage>
+                </s7:S7RequestMessage>
               </userData>
             </userData>
-          </s7:tpktMessage>
+          </s7:TpktMessage>
         </plc4x:send>
       </sc:onentry>
       <sc:transition event="success" target="receiveS7SetupCommunicationResponse"/>
@@ -211,51 +164,12 @@
 
     <sc:state id="receiveS7SetupCommunicationResponse">
       <sc:onentry>
-        <plc4x:receive timeout="5000">
-          <s7:tpktMessage>
-            <magicByte>3</magicByte>
-            <reserved>0</reserved>
-            <length><plc4x:ignore/></length>
-            <userData>
-              <headerLength>2</headerLength>
-              <type>240</type>
-              <CotpTpduData>
-                <endOfTransmission>1</endOfTransmission>
-                <tpduRef>0</tpduRef>
-              </CotpTpduData>
-              <userData>
-                <magicByte>50</magicByte>
-                <type>3</type>
-                <S7ResponseMessage>
-                  <reserved>0</reserved>
-                  <tpduReference>0</tpduReference>
-                  <parametersLength><plc4x:ignore/></parametersLength>
-                  <payloadsLength>0</payloadsLength>
-                  <errorClass><plc4x:ignore/></errorClass>
-                  <errorCode><plc4x:extract/></errorCode>
-                  <parameters>
-                    <plc4x:unordered>
-                      <parameter>
-                        <type>240</type>
-                        <S7GeneralParameterSetupCommunication>
-                          <reserved>0</reserved>
-                          <maxAmqCaller><plc4x:extract type="s7:short" name="s7-max-amq-caller"/></maxAmqCaller>
-                          <maxAmqCallee><plc4x:extract type="s7:short" name="s7-max-amq-callee"/></maxAmqCallee>
-                          <pduLength><plc4x:extract type="s7:short" name="s7-pdu-length"/></pduLength>
-                        </S7GeneralParameterSetupCommunication>
-                      </parameter>
-                      <plc4x:ignore/>
-                    </plc4x:unordered>
-                  </parameters>
-                  <payloads>
-                    <payload>
-                      <S7GeneralPayloadSetupCommunication/>
-                    </payload>
-                  </payloads>
-                </S7ResponseMessage>
-              </userData>
-            </userData>
-          </s7:tpktMessage>
+        <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>
       </sc:onentry>
       <sc:transition event="" target="sendS7IdentificationRequest"/>
@@ -265,30 +179,30 @@
 
     <sc:state id="sendS7IdentificationRequest">
       <sc:onentry>
-        <plc4x:send>
-          <s7:tpktMessage>
+        <plc4x:send socketParameterName="connection">
+          <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
             <length>33</length>
             <userData>
               <headerLength>2</headerLength>
               <type>240</type>
-              <CotpTpduData>
+              <s7:CotpTpduData>
                 <endOfTransmission>1</endOfTransmission>
                 <tpduRef>0</tpduRef>
-              </CotpTpduData>
+              </s7:CotpTpduData>
               <userData>
                 <magicByte>50</magicByte>
                 <type>7</type>
-                <S7UserDataMessage>
+                <s7:S7UserDataMessage>
                   <reserved>0</reserved>
                   <tpduReference>256</tpduReference>
                   <parametersLength>8</parametersLength>
                   <payloadsLength>8</payloadsLength>
-                  <parameters>
+                  <s7:parameters>
                     <parameter>
                       <type>0</type>
-                      <S7UserDataParameterCPUService>
+                      <s7:S7UserDataParameterCPUService>
                         <header>274</header>
                         <paramLength>4</paramLength>
                         <typeCode>17</typeCode>
@@ -296,24 +210,24 @@
                         <functionGroup>4</functionGroup>
                         <subFunctionGroup>1</subFunctionGroup>
                         <sequenceNumber>0</sequenceNumber>
-                      </S7UserDataParameterCPUService>
+                      </s7:S7UserDataParameterCPUService>
                     </parameter>
-                  </parameters>
+                  </s7:parameters>
                   <payloads>
                     <payload>
-                      <S7UserDataPayloadCpuServices>
+                      <s7:S7UserDataPayloadCpuServices>
                         <returnCode>255</returnCode>
                         <transportSize>9</transportSize>
                         <length>4</length>
                         <sslId>17</sslId>
                         <sslIndex>0</sslIndex>
-                      </S7UserDataPayloadCpuServices>
+                      </s7:S7UserDataPayloadCpuServices>
                     </payload>
                   </payloads>
-                </S7UserDataMessage>
+                </s7:S7UserDataMessage>
               </userData>
             </userData>
-          </s7:tpktMessage>
+          </s7:TpktMessage>
         </plc4x:send>
       </sc:onentry>
       <sc:transition event="success" target="receiveS7IdentificationRequest"/>
@@ -322,27 +236,27 @@
 
     <sc:state id="receiveS7IdentificationRequest">
       <sc:onentry>
-        <plc4x:receive>
-          <s7:tpktMessage>
+        <plc4x:receive socketParameterName="connection">
+          <s7:TpktMessage>
             <magicByte>3</magicByte>
             <reserved>0</reserved>
             <length><plc4x:ignore/></length>
             <userData>
               <headerLength>2</headerLength>
               <type>240</type>
-              <CotpTpduData>
+              <s7:CotpTpduData>
                 <endOfTransmission>1</endOfTransmission>
                 <tpduRef>0</tpduRef>
-              </CotpTpduData>
+              </s7:CotpTpduData>
               <userData>
                 <magicByte>50</magicByte>
                 <type>7</type>
-                <S7UserDataMessage>
+                <s7:S7UserDataMessage>
                   <reserved>0</reserved>
                   <tpduReference>256</tpduReference>
                   <parametersLength><plc4x:ignore/></parametersLength>
                   <payloadsLength><plc4x:ignore/></payloadsLength>
-                  <parameters>
+                  <s7:parameters>
                     <plc4x:unordered>
                       <parameter>
                         <type>0</type>
@@ -361,7 +275,7 @@
                       </parameter>
                       <plc4x:ignore/>
                     </plc4x:unordered>
-                  </parameters>
+                  </s7:parameters>
                   <payloads>
                     <plc4x:unordered>
                       <payload>
@@ -421,10 +335,10 @@
                       <plc4x:ignore/>
                     </plc4x:unordered>
                   </payloads>
-                </S7UserDataMessage>
+                </s7:S7UserDataMessage>
               </userData>
             </userData>
-          </s7:tpktMessage>
+          </s7:TpktMessage>
         </plc4x:receive>
       </sc:onentry>
       <sc:transition event="success" target="connected"/>
diff --git a/sandbox/dynamic-driver-s7/pom.xml b/sandbox/dynamic-driver-s7/pom.xml
index 80e9432..5dd20dd 100644
--- a/sandbox/dynamic-driver-s7/pom.xml
+++ b/sandbox/dynamic-driver-s7/pom.xml
@@ -60,6 +60,10 @@
     </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>
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 08e6e8a..790f2ef 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
@@ -38,8 +38,8 @@ public class Poc {
 
     private SCXMLExecutor executor;
 
-    public Poc() throws Exception {
-
+    private Poc() throws Exception {
+        // Initialize our PLC4X specific actions.
         List<CustomAction> customActions = new LinkedList<>();
         customActions.add(
             new CustomAction("https://plc4x.apache.org/scxml-extension", "initContext", InitContextAction.class));
@@ -50,15 +50,19 @@ public class Poc {
         customActions.add(
             new CustomAction("https://plc4x.apache.org/scxml-extension", "receive", ReceiveAction.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"),
             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);
     }
 
-    protected void run() throws Exception {
+    private void run() throws Exception {
+        // Run the state-machine.
         executor.go();
     }
 
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
new file mode 100644
index 0000000..e7bb675
--- /dev/null
+++ b/sandbox/dynamic-driver-s7/src/main/java/org/apache/plc4x/sandbox/java/s7/actions/BasePlc4xAction.java
@@ -0,0 +1,76 @@
+/*
+ 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 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;
+    }
+
+    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");
+    }
+
+    protected void logDiagnosticInformation(WithDiagnostics withDiagnostics) {
+        List<Diagnostic> diags = withDiagnostics.getDiagnostics();
+        for (Diagnostic d : diags) {
+            getLogger().error(d.getSomeMessage());
+        }
+    }
+
+}
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 490ad05..5a7a371 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
@@ -59,17 +59,18 @@ public class ConnectAction extends Action {
 
     @Override
     public void execute(ActionExecutionContext ctx) {
-        ctx.getAppLog().info("Connecting.");
+        ctx.getAppLog().info("Connecting...");
         try {
             if ("TCP".equalsIgnoreCase(type)) {
                 Socket socket = new Socket(host, Integer.parseInt(port));
-                TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).data(socket).build();
+                ctx.getGlobalContext().set("connection", socket);
+                TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
                 ctx.getInternalIOProcessor().addEvent(event);
+                ctx.getAppLog().info("Connected.");
             }
         } catch (IOException e) {
             e.printStackTrace();
         }
-        return;
     }
 
 }
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 9285c64..6b6e5f4 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
@@ -23,14 +23,62 @@ 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 {
 
+    private static final Logger logger = LoggerFactory.getLogger(InitContextAction.class);
+
     @Override
     public void execute(ActionExecutionContext ctx) {
         ctx.getAppLog().info("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();
+                ProcessorFactory pf = c.compileSource(schemaUri);
+                if (pf.isError()) {
+                    logDiagnosticInformation(pf);
+                    TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).build();
+                    ctx.getInternalIOProcessor().addEvent(event);
+                    return;
+                }
+                DataProcessor dp = pf.onPath("/");
+                if (dp.isError()) {
+                    logDiagnosticInformation(dp);
+                    TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).build();
+                    ctx.getInternalIOProcessor().addEvent(event);
+                    return;
+                }
+                ctx.getGlobalContext().set("dfdl", dp);
+            }
+        } catch (IOException | URISyntaxException e) {
+            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);
     }
 
+    private void logDiagnosticInformation(WithDiagnostics withDiagnostics) {
+        List<Diagnostic> diags = withDiagnostics.getDiagnostics();
+        for (Diagnostic d : diags) {
+            logger.error(d.getSomeMessage());
+        }
+    }
+
 }
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 f6f62c0..d17d937 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
@@ -22,12 +22,46 @@ 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.NodeListValue;
+import org.apache.commons.scxml2.model.NodeValue;
+import org.apache.commons.scxml2.model.ParsedValue;
+import org.apache.daffodil.japi.DataProcessor;
+import org.apache.daffodil.japi.ParseResult;
+import org.apache.daffodil.japi.infoset.W3CDOMInfosetOutputter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
-public class ReceiveAction extends Action {
+import java.io.BufferedReader;
+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;
+
+public class ReceiveAction extends BasePlc4xAction {
 
     private String timeout;
 
+    private final Map<String, String> verificationRules;
+    private final Map<String, String> extractionRules;
+
+    public ReceiveAction() {
+        verificationRules = new HashMap<>();
+        extractionRules = new HashMap<>();
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return LoggerFactory.getLogger(ReceiveAction.class);
+    }
+
     public String getTimeout() {
         return timeout;
     }
@@ -37,8 +71,73 @@ public class ReceiveAction extends Action {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
+    public void setParsedValue(ParsedValue parsedValue) {
+        super.setParsedValue(parsedValue);
+
+        if(parsedValue != null) {
+            if(parsedValue instanceof NodeListValue) {
+                List<Node> ruleList = (List<Node>) parsedValue.getValue();
+                for (Node node : ruleList) {
+                    if(node instanceof Element) {
+                        parseElement((Element) node);
+                    }
+                }
+            } else if(parsedValue instanceof NodeValue) {
+                parseElement((Element) parsedValue.getValue());
+            }
+        }
+    }
+
+    private void parseElement(Element ruleElement) {
+        String name = ruleElement.getAttribute("name");
+        String xpath = ruleElement.getAttribute("xpath");
+        if("verification".equals(ruleElement.getTagName())) {
+            verificationRules.put(name, xpath);
+        } else if("extraction".equals(ruleElement.getTagName())) {
+            extractionRules.put(name, xpath);
+        } else {
+            getLogger().error("unsupported rule type: " + ruleElement.getTagName());
+        }
+    }
+
+    @Override
     public void execute(ActionExecutionContext ctx) {
         ctx.getAppLog().info("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);
+                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(connection.getInputStream());
+            ReadableByteChannel rbc = Channels.newChannel(inputStream);
+            W3CDOMInfosetOutputter outputter = new W3CDOMInfosetOutputter();
+            ParseResult byteMessage = dp.parse(rbc, outputter);
+            if (byteMessage.isError()) {
+                logDiagnosticInformation(byteMessage);
+                return;
+            }
+
+            Document message = outputter.getResult();
+            System.out.println(message);
+            ctx.getAppLog().info("Successfully sent message.");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
         TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
         ctx.getInternalIOProcessor().addEvent(event);
     }
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 392d0c5..f761ac3 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
@@ -22,13 +22,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.apache.commons.scxml2.model.ParsedValue;
-import org.apache.commons.scxml2.model.ParsedValueContainer;
-import org.apache.daffodil.japi.Compiler;
-import org.apache.daffodil.japi.*;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
@@ -38,88 +38,58 @@ import javax.xml.parsers.ParserConfigurationException;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.net.Socket;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
 import java.nio.channels.Channels;
 import java.nio.channels.WritableByteChannel;
-import java.util.List;
 
-public class SendAction extends Action implements ParsedValueContainer {
-
-    private ParsedValue message;
-
-    @Override
-    public ParsedValue getParsedValue() {
-        return message;
-    }
+public class SendAction extends BasePlc4xAction {
 
     @Override
-    public void setParsedValue(ParsedValue parsedValue) {
-        message = parsedValue;
+    protected Logger getLogger() {
+        return LoggerFactory.getLogger(SendAction.class);
     }
 
     @Override
     public void execute(ActionExecutionContext ctx) {
-        if(message != null) {
-            if(message.getType() == ParsedValue.ValueType.NODE) {
+        ctx.getAppLog().info("Sending.");
+        if(getParsedValue() != null) {
+            if(getParsedValue().getType() == ParsedValue.ValueType.NODE) {
                 try {
-                    Node messageTemplate = (Node) message.getValue();
+                    Node messageTemplate = (Node) getParsedValue().getValue();
                     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                     DocumentBuilder builder = dbf.newDocumentBuilder();
                     Document doc = builder.newDocument();
                     Node messageTemplateClone = doc.importNode(messageTemplate, true);
                     doc.appendChild(messageTemplateClone);
-                    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();
-                        ProcessorFactory pf = c.compileSource(schemaUri);
-                        if(pf.isError()) {
-                            List<Diagnostic> diags = pf.getDiagnostics();
-                            for (Diagnostic d : diags) {
-                                System.err.println(d.getSomeMessage());
-                            }
-                            return;
-                        }
-                        DataProcessor dp = pf.onPath("/");
-                        if(dp.isError()) {
-                            List<Diagnostic> diags = dp.getDiagnostics();
-                            for (Diagnostic d : diags) {
-                                System.err.println(d.getSomeMessage());
-                            }
-                            return;
-                        }
-                        InfosetInputter inputter = new W3CDOMInfosetInputter(doc);
-
-                        Socket connection = (Socket) ctx.getGlobalContext().get("connection");
-                        DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
-                        WritableByteChannel wbc = Channels.newChannel(outputStream);
 
-                        UnparseResult byteMessage = dp.unparse(inputter, wbc);
-                        if(byteMessage.isError()) {
-                            List<Diagnostic> diags = byteMessage.getDiagnostics();
-                            for (Diagnostic d : diags) {
-                                System.err.println(d.getSomeMessage());
-                            }
-                            return;
-                        }
+                    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);
+                        return;
+                    }
+                    InfosetInputter inputter = new W3CDOMInfosetInputter(doc);
 
-                        outputStream.flush();
+                    Socket connection = getSocket(ctx);
+                    DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
+                    WritableByteChannel wbc = Channels.newChannel(outputStream);
+                    UnparseResult byteMessage = dp.unparse(inputter, wbc);
+                    if(byteMessage.isError()) {
+                        logDiagnosticInformation(byteMessage);
+                        return;
                     }
-                } catch(URISyntaxException e) {
-                    e.printStackTrace();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                } catch (ParserConfigurationException e) {
+                    outputStream.flush();
+                    ctx.getAppLog().info("Successfully sent message.");
+                } catch(IOException | ParserConfigurationException e) {
                     e.printStackTrace();
                 }
-            } else if(message.getType() == ParsedValue.ValueType.JSON) {
-
+            } else {
+                TriggerEvent event = new EventBuilder("failure", TriggerEvent.SIGNAL_EVENT).
+                    data("type '" + getParsedValue().getType() + "' not supported").build();
+                ctx.getInternalIOProcessor().addEvent(event);
+                return;
             }
         }
-        ctx.getAppLog().info("Sending.");
         TriggerEvent event = new EventBuilder("success", TriggerEvent.SIGNAL_EVENT).build();
         ctx.getInternalIOProcessor().addEvent(event);
     }