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.