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/08/23 17:07:20 UTC

[plc4x] branch develop updated: - Implement a first partially working passive S7 driver. - Fixed some issues in the S7 mspec - Fixed some issues with optional fields in the code generation - Extended the mspec antlr4 grammar to support "/" and "*" operations

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/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 6220138  - Implement a first partially working passive S7 driver. - Fixed some issues in the S7 mspec - Fixed some issues with optional fields in the code generation - Extended the mspec antlr4 grammar to support "/" and "*" operations
6220138 is described below

commit 6220138c30e8ad1ab71f106661752aee2b65cdf5
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Fri Aug 23 19:07:13 2019 +0200

    - Implement a first partially working passive S7 driver.
    - Fixed some issues in the S7 mspec
    - Fixed some issues with optional fields in the code generation
    - Extended the mspec antlr4 grammar to support "/" and "*" operations
---
 .../templates/java/active-io-template.ftlh         |  2 +-
 .../templates/java/passive-io-template.ftlh        |  2 +-
 .../resources/templates/java/pojo-template.ftlh    |  4 +
 .../plugins/codegenerator/language/mspec/MSpec.g4  |  2 +
 .../base/connection/RawSocketChannelFactory.java   |  3 +
 ...SocketChannelOption.java => PacketHandler.java} | 10 +--
 .../utils/rawsockets/netty/RawSocketChannel.java   | 11 ++-
 .../rawsockets/netty/RawSocketChannelConfig.java   | 32 ++++++-
 .../rawsockets/netty/RawSocketChannelOption.java   |  3 +-
 ...tChannelConfig.java => TcpIpPacketHandler.java} | 21 ++---
 .../s7/src/main/resources/protocols/s7/s7.mspec    | 14 ++--
 sandbox/test-java-passive-s7-driver/pom.xml        | 10 +++
 .../plc4x/javapassive/s7/PassiveS7PlcDriver.java   | 89 ++++++++++++++++++++
 .../s7/connection/PassiveS7PlcConnection.java      | 98 ++++++++++++++++++++++
 .../s7/protocol/HelloWorldProtocol.java            | 48 +++++++++++
 .../javapassive/s7/protocol/PassiveS7Protocol.java | 62 ++++++++++++++
 .../services/org.apache.plc4x.java.spi.PlcDriver   | 19 +++++
 .../asciidoc/developers/code-gen/protocol/df1.adoc | 19 ++++-
 18 files changed, 419 insertions(+), 30 deletions(-)

diff --git a/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh
index d6770a8..50cafe8 100644
--- a/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/active-io-template.ftlh
@@ -227,7 +227,7 @@ public class ${typeName}IO implements MessageIO<${typeName}<#if helper.isDiscrim
 
         // Optional Field (${field.name}) (Can be skipped, if a given expression evaluates to false)
         ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
-        if(${helper.toDeserializationExpression(field.conditionExpression, type.parserArguments)}) {
+        if(${helper.toDeserializationExpression(field.conditionExpression, type.parserArguments)?no_esc}) {
             ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io);</#if>;
         }
         <#break>
diff --git a/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh
index c354b00..92f63de 100644
--- a/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/passive-io-template.ftlh
@@ -227,7 +227,7 @@ public class ${typeName}IO implements MessageInput<${typeName}<#if helper.isDisc
 
         // Optional Field (${field.name}) (Can be skipped, if a given expression evaluates to false)
         ${helper.getLanguageTypeNameForField(field)} ${field.name} = ${helper.getNullValueForType(field.type)};
-        if(${helper.toDeserializationExpression(field.conditionExpression, type.parserArguments)}) {
+        if(${helper.toDeserializationExpression(field.conditionExpression, type.parserArguments)?no_esc}) {
             ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name?uncap_first}IO.parse(io);</#if>;
         }
         <#break>
diff --git a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
index 066a303..628e4ce 100644
--- a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
@@ -150,7 +150,11 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 
         // Optional Field (${field.name})
         if(${field.name} != null) {
+        <#if helper.isSimpleType(field.type)>
             lengthInBits += ${field.type.size};
+        <#else>
+            lengthInBits += ${field.name}.getLengthInBytes() * 8;
+        </#if>
         }
         <#break>
     <#case "padding">
diff --git a/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 b/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
index ad94f70..b049b80 100644
--- a/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
+++ b/build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
@@ -187,6 +187,8 @@ RCBRACKET : '}';
 BinaryOperator
  : '+'
  | '-'
+ | '/'
+ | '*'
  | '=='
  | '!='
  | '>'
diff --git a/plc4j/protocols/driver-bases/raw-socket/src/main/java/org/apache/plc4x/java/base/connection/RawSocketChannelFactory.java b/plc4j/protocols/driver-bases/raw-socket/src/main/java/org/apache/plc4x/java/base/connection/RawSocketChannelFactory.java
index 7fac64a..fbaa680 100644
--- a/plc4j/protocols/driver-bases/raw-socket/src/main/java/org/apache/plc4x/java/base/connection/RawSocketChannelFactory.java
+++ b/plc4j/protocols/driver-bases/raw-socket/src/main/java/org/apache/plc4x/java/base/connection/RawSocketChannelFactory.java
@@ -26,7 +26,9 @@ import io.netty.util.concurrent.GenericFutureListener;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketChannel;
+import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketChannelOption;
 import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
+import org.apache.plc4x.java.utils.rawsockets.netty.TcpIpPacketHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,6 +61,7 @@ public class RawSocketChannelFactory implements ChannelFactory {
             Bootstrap bootstrap = new Bootstrap();
             bootstrap.group(workerGroup);
             bootstrap.channel(RawSocketChannel.class);
+            bootstrap.option(RawSocketChannelOption.PACKET_HANDLER, new TcpIpPacketHandler());
             bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
             bootstrap.option(ChannelOption.TCP_NODELAY, true);
             // TODO we should use an explicit (configurable?) timeout here
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/PacketHandler.java
similarity index 73%
copy from plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java
copy to plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/PacketHandler.java
index a1793be..6afcc3a 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/PacketHandler.java
@@ -18,14 +18,10 @@ under the License.
 */
 package org.apache.plc4x.java.utils.rawsockets.netty;
 
-import io.netty.channel.ChannelOption;
+import org.pcap4j.packet.Packet;
 
-public class RawSocketChannelOption<T> extends ChannelOption<T> {
+public interface PacketHandler {
 
-    public static final ChannelOption<Boolean> SOME_OPTION = valueOf(RawSocketChannelOption.class, "SOME_OPTION");
-
-    protected RawSocketChannelOption() {
-        super(null);
-    }
+    byte[] getData(Packet packet);
 
 }
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
index 65f1e26..a83cb96 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
@@ -28,6 +28,7 @@ import io.netty.channel.oio.OioByteStreamChannel;
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.plc4x.java.utils.rawsockets.RawSocketException;
 import org.pcap4j.core.*;
+import org.pcap4j.packet.Packet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,9 +48,10 @@ public class RawSocketChannel extends OioByteStreamChannel {
 
     private static final Logger logger = LoggerFactory.getLogger(RawSocketChannel.class);
 
+    private final RawSocketChannelConfig config;
+
     private RawSocketAddress remoteRawSocketAddress;
     private SocketAddress localAddress;
-    private final RawSocketChannelConfig config;
     private PcapHandle handle;
     private Thread loopThread;
 
@@ -108,7 +110,12 @@ public class RawSocketChannel extends OioByteStreamChannel {
         // forwards the bytes read to the buffer.
         loopThread = new Thread(() -> {
             try {
-                handle.loop(-1, (PacketListener) packet -> buffer.writeBytes(packet.getRawData()));
+                handle.loop(-1, new PacketListener() {
+                    @Override
+                    public void gotPacket(Packet packet) {
+                        buffer.writeBytes(config.getPacketHandler().getData(packet));
+                    }
+                });
             } catch (PcapNativeException | NotOpenException e) {
                 // TODO this should close everything automatically
                 logger.error("Pcap4j loop thread died!", e);
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java
index 96d28d8..8b2b401 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java
@@ -19,18 +19,48 @@ under the License.
 package org.apache.plc4x.java.utils.rawsockets.netty;
 
 import io.netty.channel.*;
+import org.pcap4j.packet.Packet;
 
 import java.util.Map;
 
 public class RawSocketChannelConfig extends DefaultChannelConfig implements ChannelConfig {
 
+    private PacketHandler packetHandler;
+
     public RawSocketChannelConfig(Channel channel) {
         super(channel);
+        packetHandler = new PacketHandler() {
+            @Override
+            public byte[] getData(Packet packet) {
+                return packet.getRawData();
+            }
+        };
     }
 
     @Override
     public Map<ChannelOption<?>, Object> getOptions() {
-        return getOptions(super.getOptions(), RawSocketChannelOption.SOME_OPTION);
+        return getOptions(super.getOptions(), RawSocketChannelOption.PACKET_HANDLER);
+    }
+
+    @Override
+    public <T> boolean setOption(ChannelOption<T> option, T value) {
+        if(option == RawSocketChannelOption.PACKET_HANDLER) {
+            if(value instanceof PacketHandler) {
+                packetHandler = (PacketHandler) value;
+                return true;
+            }
+            return false;
+        } else {
+            return super.setOption(option, value);
+        }
+    }
+
+    public void setPacketHandler(PacketHandler packetHandler) {
+        this.packetHandler = packetHandler;
+    }
+
+    public PacketHandler getPacketHandler() {
+        return packetHandler;
     }
 
 }
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java
index a1793be..004f0ca 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelOption.java
@@ -22,7 +22,8 @@ import io.netty.channel.ChannelOption;
 
 public class RawSocketChannelOption<T> extends ChannelOption<T> {
 
-    public static final ChannelOption<Boolean> SOME_OPTION = valueOf(RawSocketChannelOption.class, "SOME_OPTION");
+    public static final ChannelOption<PacketHandler> PACKET_HANDLER =
+        ChannelOption.valueOf(PacketHandler.class, "PACKET_HANDLER");
 
     protected RawSocketChannelOption() {
         super(null);
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/TcpIpPacketHandler.java
similarity index 59%
copy from plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java
copy to plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/TcpIpPacketHandler.java
index 96d28d8..64a1e5b 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelConfig.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/TcpIpPacketHandler.java
@@ -18,19 +18,20 @@ under the License.
 */
 package org.apache.plc4x.java.utils.rawsockets.netty;
 
-import io.netty.channel.*;
+import org.pcap4j.packet.*;
 
-import java.util.Map;
-
-public class RawSocketChannelConfig extends DefaultChannelConfig implements ChannelConfig {
-
-    public RawSocketChannelConfig(Channel channel) {
-        super(channel);
-    }
+public class TcpIpPacketHandler implements PacketHandler {
 
     @Override
-    public Map<ChannelOption<?>, Object> getOptions() {
-        return getOptions(super.getOptions(), RawSocketChannelOption.SOME_OPTION);
+    public byte[] getData(Packet packet) {
+        EthernetPacket ethernetPacket = (EthernetPacket) packet;
+        IpV4Packet ipv4Packet = (IpV4Packet) ethernetPacket.getPayload();
+        TcpPacket tcpPacket = (TcpPacket) ipv4Packet.getPayload();
+        if(tcpPacket.getPayload() instanceof UnknownPacket) {
+            UnknownPacket unknownPacket = (UnknownPacket) tcpPacket.getPayload();
+            return tcpPacket.getPayload().getRawData();
+        }
+        return new byte[0];
     }
 
 }
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index be9e6f4..025678f 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -25,14 +25,14 @@
     [const    uint 8     'protocolId' '0x03']
     [reserved uint 8     '0x00']
     [implicit uint 16    'len'        'payload.lengthInBytes + 4']
-    [simple   COTPPacket 'payload']
+    [simple   COTPPacket 'payload' ['len - 4']]
 ]
 
 ////////////////////////////////////////////////////////////////
 // COTP
 ////////////////////////////////////////////////////////////////
 
-[discriminatedType 'COTPPacket'
+[discriminatedType 'COTPPacket' [uint 16 'cotpLen']
     [implicit      uint 8 'headerLength' 'lengthInBytes - (payload.lengthInBytes + 1)']
     [discriminator uint 8 'tpduCode']
     [typeSwitch 'tpduCode'
@@ -64,12 +64,13 @@
             [simple uint 8  'rejectCause']
         ]
     ]
-    [array  COTPParameter 'parameters' length '(headerLength + 1) - curPos' ['(headerLength + 1) - curPos']]
-    [simple S7Message     'payload']
+    [array    COTPParameter 'parameters' length '(headerLength + 1) - curPos' ['(headerLength + 1) - curPos']]
+    [optional S7Message     'payload'    'curPos < cotpLen']
 ]
 
 [discriminatedType 'COTPParameter' [uint 8 'rest']
     [discriminator uint 8 'parameterType']
+    [implicit      uint 8 'parameterLength' 'lengthInBytes - 2']
     [typeSwitch 'parameterType'
         ['0xC0' COTPParameterTpduSize
             [simple uint 8 'tpduSize']
@@ -209,12 +210,13 @@
     ]
 ]
 
+// This is actually not quite correct as depending pon the transportSize the length is either defined in bits or bytes.
 [type 'S7VarPayloadDataItem'
     [simple  uint 8  'returnCode']
     [simple  uint 8  'transportSize']
     [simple  uint 16 'dataLength']
-    [array   uint 8  'data' count 'dataLength']
-    [padding uint 8  'pad' '0x00' 'dataLength % 2 == 1']
+    [array   uint 8  'data' count 'dataLength / 8']
+    [padding uint 8  'pad' '0x00' '(dataLength / 8) % 2 == 1']
 ]
 
 [type 'S7VarPayloadStatusItem'
diff --git a/sandbox/test-java-passive-s7-driver/pom.xml b/sandbox/test-java-passive-s7-driver/pom.xml
index dc25643..4720867 100644
--- a/sandbox/test-java-passive-s7-driver/pom.xml
+++ b/sandbox/test-java-passive-s7-driver/pom.xml
@@ -57,10 +57,20 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
       <artifactId>plc4j-utils-driver-base-java</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
     <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-raw-socket</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
     </dependency>
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/PassiveS7PlcDriver.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/PassiveS7PlcDriver.java
new file mode 100644
index 0000000..05b0871
--- /dev/null
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/PassiveS7PlcDriver.java
@@ -0,0 +1,89 @@
+/*
+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.javapassive.s7;
+
+import org.apache.plc4x.java.PlcDriverManager;
+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.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.spi.PlcDriver;
+import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketAddress;
+import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
+import org.apache.plc4x.javapassive.s7.connection.PassiveS7PlcConnection;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Implementation of the S7 protocol, based on:
+ * - S7 Protocol
+ * - ISO Transport Protocol (Class 0) (https://tools.ietf.org/html/rfc905)
+ * - ISO on TCP (https://tools.ietf.org/html/rfc1006)
+ * - TCP
+ */
+public class PassiveS7PlcDriver implements PlcDriver {
+
+    private static final int ISO_ON_TCP_PORT = 102;
+
+    private static final Pattern S7_URI_PATTERN = Pattern.compile("^s7-passive://(?<networkDevice>.*)(?<params>\\?.*)?");
+
+    @Override
+    public String getProtocolCode() {
+        return "s7-passive";
+    }
+
+    @Override
+    public String getProtocolName() {
+        return "Siemens S7 (Passive-Mode)";
+    }
+
+    @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-passive://{network-device}'");
+        }
+        String networkDevice = matcher.group("networkDevice");
+
+        String params = matcher.group("params") != null ? matcher.group("params").substring(1) : null;
+
+        try {
+            RawSocketIpAddress rawSocketAddress = new RawSocketIpAddress(
+                networkDevice, RawSocketIpAddress.ALL_PROTOCOLS, null, ISO_ON_TCP_PORT);
+            return new PassiveS7PlcConnection(rawSocketAddress, params);
+        } 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.");
+    }
+
+    public static void main(String[] args) throws Exception {
+        try (PlcConnection connection = new PlcDriverManager().getConnection("s7-passive://en10")) {
+            PlcReadRequest readRequest = connection.readRequestBuilder().addItem("hurz", "lalala").build();
+            readRequest.execute().get();
+        }
+    }
+
+}
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/connection/PassiveS7PlcConnection.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/connection/PassiveS7PlcConnection.java
new file mode 100644
index 0000000..04245ec
--- /dev/null
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/connection/PassiveS7PlcConnection.java
@@ -0,0 +1,98 @@
+/*
+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.javapassive.s7.connection;
+
+import io.netty.channel.*;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.base.connection.ChannelFactory;
+import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.base.connection.NettyPlcConnection;
+import org.apache.plc4x.java.base.connection.RawSocketChannelFactory;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.DefaultPlcReadRequest;
+import org.apache.plc4x.java.base.messages.PlcReader;
+import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
+import org.apache.plc4x.javapassive.s7.protocol.HelloWorldProtocol;
+import org.apache.plc4x.javapassive.s7.protocol.PassiveS7Protocol;
+
+import java.util.concurrent.CompletableFuture;
+
+public class PassiveS7PlcConnection extends NettyPlcConnection implements PlcReader {
+
+    public PassiveS7PlcConnection(RawSocketIpAddress address, String params) {
+        this(new RawSocketChannelFactory(address.getDeviceName(), null,
+            102, -1), params);
+    }
+
+    public PassiveS7PlcConnection(ChannelFactory channelFactory, String param) {
+        super(channelFactory, false);
+    }
+
+    @Override
+    protected ChannelHandler getChannelHandler(CompletableFuture<Void> sessionSetupCompleteFuture) {
+        return new ChannelInitializer() {
+            @Override
+            protected void initChannel(Channel channel) {
+                // Build the protocol stack for communicating with the s7 protocol.
+                ChannelPipeline pipeline = channel.pipeline();
+                pipeline.addLast(new ChannelInboundHandlerAdapter() {
+                    @Override
+                    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+                        if (evt instanceof ConnectedEvent) {
+                            sessionSetupCompleteFuture.complete(null);
+                        } else {
+                            super.userEventTriggered(ctx, evt);
+                        }
+                    }
+                });
+                pipeline.addLast(new PassiveS7Protocol());
+                pipeline.addLast(new HelloWorldProtocol());
+            }
+        };
+    }
+
+    @Override
+    public boolean canRead() {
+        return true;
+    }
+
+    @Override
+    public PlcReadRequest.Builder readRequestBuilder() {
+        return new DefaultPlcReadRequest.Builder(this, new DefaultPlcFieldHandler() {
+            @Override
+            public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+                return new PlcField() {
+                    @Override
+                    public Class<?> getDefaultJavaType() {
+                        return String.class;
+                    }
+                };
+            }
+        });
+    }
+
+    @Override
+    public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+        return new CompletableFuture<>();
+    }
+
+}
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java
new file mode 100644
index 0000000..bec33bd
--- /dev/null
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/HelloWorldProtocol.java
@@ -0,0 +1,48 @@
+/*
+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.javapassive.s7.protocol;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.javapassive.s7.S7Message;
+import org.apache.plc4x.javapassive.s7.TPKTPacket;
+
+import java.util.List;
+
+public class HelloWorldProtocol extends PlcMessageToMessageCodec<TPKTPacket, PlcRequestContainer> {
+
+    @Override
+    protected void encode(ChannelHandlerContext channelHandlerContext, PlcRequestContainer plcRequestContainer, List<Object> list) throws Exception {
+        System.out.println(plcRequestContainer);
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext channelHandlerContext, TPKTPacket tpktPacket, List<Object> list) throws Exception {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[").append(tpktPacket.getPayload().getClass().getName());
+        if(tpktPacket.getPayload().getPayload() != null) {
+            S7Message s7Message = tpktPacket.getPayload().getPayload();
+            sb.append(" \n  [").append(s7Message.getClass()).append("]\n");
+        }
+        sb.append("]");
+        System.out.println(sb.toString());
+    }
+
+}
diff --git a/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java
new file mode 100644
index 0000000..a758e71
--- /dev/null
+++ b/sandbox/test-java-passive-s7-driver/src/main/java/org/apache/plc4x/javapassive/s7/protocol/PassiveS7Protocol.java
@@ -0,0 +1,62 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.javapassive.s7.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.plc4x.java.base.PlcByteToMessageCodec;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.javapassive.s7.TPKTPacket;
+import org.apache.plc4x.javapassive.s7.io.TPKTPacketIO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class PassiveS7Protocol extends PlcByteToMessageCodec<TPKTPacket> {
+
+    private static final Logger logger = LoggerFactory.getLogger(PassiveS7Protocol.class);
+
+    private TPKTPacketIO io;
+
+    public PassiveS7Protocol() {
+        io = new TPKTPacketIO();
+    }
+
+    @Override
+    protected void encode(ChannelHandlerContext channelHandlerContext, TPKTPacket tpktPacket, ByteBuf byteBuf) throws Exception {
+        System.out.println(tpktPacket);
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out) throws Exception {
+        byte[] bytes = new byte[byteBuf.readableBytes()];
+        byteBuf.readBytes(bytes);
+        ReadBuffer readBuffer = new ReadBuffer(bytes);
+        while(readBuffer.getPos() < bytes.length) {
+            try {
+                TPKTPacket packet = io.parse(readBuffer);
+                out.add(packet);
+            } catch(Exception e) {
+                logger.warn("Error decoding package: " + e.getMessage());
+            }
+        }
+    }
+
+}
diff --git a/sandbox/test-java-passive-s7-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-passive-s7-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
new file mode 100644
index 0000000..df3c9a7
--- /dev/null
+++ b/sandbox/test-java-passive-s7-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -0,0 +1,19 @@
+#
+# 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.javapassive.s7.PassiveS7PlcDriver
diff --git a/src/site/asciidoc/developers/code-gen/protocol/df1.adoc b/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
index 4186a2d..a598cad 100644
--- a/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
+++ b/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
@@ -1,4 +1,21 @@
-= Example: DF1 MSpec
+//
+//  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.
+//
+
+== Example: DF1 MSpec
 
 The DF1 protocol has three basic messages: a command message, acknowledge and not acknowledge.
 A `0x10` is used as delimiter to differentiate between the messages and parts of the command message.