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/07 08:48:02 UTC

[plc4x] 15/17: - Tweaked the mspec for the DF1 protocol - Started implementing a PLC4X driver based on the generated code

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

cdutz pushed a commit to branch feature/implement-df1-driver
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 40dbc1bf73d239a6ab9d41e9ae75b5304b80b9ac
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Aug 6 17:03:35 2019 +0200

    - Tweaked the mspec for the DF1 protocol
    - Started implementing a PLC4X driver based on the generated code
---
 .../org/apache/plc4x/java/utils/WriteBuffer.java   |  21 ++
 .../main/resources/protocols/df1/protocol.mspec    |  18 +-
 sandbox/test-java-df1-driver/README.adoc           |  35 +++
 sandbox/test-java-df1-driver/pom.xml               |  25 +++
 .../org/apache/plc4x/java/df1/DF1PlcDriver.java    |  73 ++++++
 .../java/df1/connection/BaseDf1Connection.java     |  34 +++
 .../java/df1/connection/SerialDf1Connection.java   | 112 ++++++++++
 .../org/apache/plc4x/java/df1/fields/DataType.java |  17 ++
 .../plc4x/java/df1/protocol/Df1Protocol.java       | 143 ++++++++++++
 .../plc4x/java/df1/protocol/Plc4XDf1Protocol.java  |  40 ++++
 .../plc4x/java/df1/util/Df1FieldHandler.java       |  38 ++++
 .../plc4x/protocol/df1/BenchmarkGeneratedDf1.java  | 247 ---------------------
 .../org/apache/plc4x/protocol/df1/DF1Utils.java    |  58 ++++-
 .../services/org.apache.plc4x.java.spi.PlcDriver   |  19 ++
 .../plc4x/protocol/df1/BenchmarkGeneratedDf1.java  |  84 +++++++
 .../plc4x/protocol/df1/BenchmarkManualDf1.java     |   4 +-
 16 files changed, 711 insertions(+), 257 deletions(-)

diff --git a/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java b/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
index 35283c5..bc10358 100644
--- a/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
+++ b/plc4j/utils/driver-base-java/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
@@ -33,11 +33,17 @@ public class WriteBuffer {
     private ByteBuffer bb;
     private BufferByteOutput bbo;
     private BitOutput bo;
+    private boolean littleEndian;
 
     public WriteBuffer(int size) {
+        this(size, true);
+    }
+
+    public WriteBuffer(int size, boolean littleEndian) {
         bb = ByteBuffer.allocate(size);
         bbo = new BufferByteOutput<>(bb);
         bo = new DefaultBitOutput<>(bbo);
+        this.littleEndian = littleEndian;
     }
 
     public byte[] getData() {
@@ -88,6 +94,9 @@ public class WriteBuffer {
             throw new ParseException("unsigned int can only contain max 16 bits");
         }
         try {
+            if(!littleEndian) {
+                value = Integer.reverseBytes(value) >> 16;
+            }
             bo.writeInt(true, bitLength, value);
         } catch (IOException e) {
             throw new ParseException("Error reading", e);
@@ -102,6 +111,9 @@ public class WriteBuffer {
             throw new ParseException("unsigned long can only contain max 32 bits");
         }
         try {
+            if(!littleEndian) {
+                value = Long.reverseBytes(value) >> 32;
+            }
             bo.writeLong(true, bitLength, value);
         } catch (IOException e) {
             throw new ParseException("Error reading", e);
@@ -134,6 +146,9 @@ public class WriteBuffer {
             throw new ParseException("short can only contain max 16 bits");
         }
         try {
+            if(!littleEndian) {
+                value = Short.reverseBytes(value);
+            }
             bo.writeShort(false, bitLength, value);
         } catch (IOException e) {
             throw new ParseException("Error reading", e);
@@ -148,6 +163,9 @@ public class WriteBuffer {
             throw new ParseException("int can only contain max 32 bits");
         }
         try {
+            if(!littleEndian) {
+                value = Integer.reverseBytes(value);
+            }
             bo.writeInt(false, bitLength, value);
         } catch (IOException e) {
             throw new ParseException("Error reading", e);
@@ -162,6 +180,9 @@ public class WriteBuffer {
             throw new ParseException("long can only contain max 64 bits");
         }
         try {
+            if(!littleEndian) {
+                value = Long.reverseBytes(value);
+            }
             bo.writeLong(false, bitLength, value);
         } catch (IOException e) {
             throw new ParseException("Error reading", e);
diff --git a/protocols/df1/src/main/resources/protocols/df1/protocol.mspec b/protocols/df1/src/main/resources/protocols/df1/protocol.mspec
index ce5a8f5..d63974c 100644
--- a/protocols/df1/src/main/resources/protocols/df1/protocol.mspec
+++ b/protocols/df1/src/main/resources/protocols/df1/protocol.mspec
@@ -18,14 +18,18 @@
 //
 
 
-[type 'DF1ReadRequest'
-    [field    DF1SymbolMessageFrameStart    'messageFrameStart' ['0', 'null']]
-    [field    DF1SymbolMessageFrameEnd      'messageFrameEnd' ['0', 'messageFrameStart']]
+[type 'ReadRequest'
+    [field    DF1Symbol    'messageFrameStart' ['0', 'null']]
+    [field    DF1Symbol    'messageFrameEnd' ['0', 'messageFrameStart']]
 ]
 
-[type 'DF1ReadResponse' [uint 8 'payloadSize']
-    [field    DF1SymbolMessageFrameStart    'messageFrameStart' ['payloadSize', 'null']]
-    [field    DF1SymbolMessageFrameEnd      'messageFrameEnd' ['0', 'messageFrameStart']]
+[type 'ReadResponse' [uint 8 'payloadSize']
+    [field    DF1Symbol    'messageFrameStart' ['payloadSize', 'null']]
+    [field    DF1Symbol    'messageFrameEnd' ['0', 'messageFrameStart']]
+]
+
+[type 'Result'
+    [field    DF1Symbol    'result' ['0', 'null']]
 ]
 
 [discriminatedType 'DF1Symbol' [uint 8 'payloadSize', DF1SymbolMessageFrameStart 'messageStartSymbol']
@@ -38,7 +42,7 @@
             [field    DF1Command   'command' ['payloadSize']]
         ]
         ['0x03' DF1SymbolMessageFrameEnd
-            [implicit uint 16      'crc' 'STATIC_CALL("org.apache.plc4x.protocol.df1.DF1Utils.CRCCheck", messageStartSymbol.destinationAddress, messageStartSymbol.sourceAddress, messageStartSymbol.command.discriminatorValues, messageStartSymbol.command.status, messageStartSymbol.command.transactionCounter, discriminatorValues[0])']
+            [implicit uint 16      'crc' 'STATIC_CALL("org.apache.plc4x.protocol.df1.DF1Utils.CRCCheck", discriminatorValues[0], messageStartSymbol)']
         ]
         ['0x06' DF1SymbolMessageFrameACK
         ]
diff --git a/sandbox/test-java-df1-driver/README.adoc b/sandbox/test-java-df1-driver/README.adoc
new file mode 100644
index 0000000..d513383
--- /dev/null
+++ b/sandbox/test-java-df1-driver/README.adoc
@@ -0,0 +1,35 @@
+//
+//  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.
+//
+
+== Using the Driver in the hello-world example
+
+Add the driver to the pom.xml
+
+        <dependency>
+          <groupId>org.apache.plc4x.sandbox</groupId>
+          <artifactId>test-java-df1-driver</artifactId>
+          <version>0.5.0-SNAPSHOT</version>
+          <scope>runtime</scope>
+        </dependency>
+
+Then start the Hello world (Ideally in IntelliJ) with the following program arguments:
+
+    df1:serial///{com-port-name} {address}
+
+Currently the parsing of addresses is not implemented yet, so it will not work.
+
+But as soon as that's done, this should work.
\ No newline at end of file
diff --git a/sandbox/test-java-df1-driver/pom.xml b/sandbox/test-java-df1-driver/pom.xml
index 3ddc53b..1cccdd6 100644
--- a/sandbox/test-java-df1-driver/pom.xml
+++ b/sandbox/test-java-df1-driver/pom.xml
@@ -57,9 +57,34 @@
   <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-protocol-driver-base</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-tcp</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-serial</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>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java
new file mode 100644
index 0000000..fd8e0c6
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/DF1PlcDriver.java
@@ -0,0 +1,73 @@
+/*
+ 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.java.df1;
+
+import org.apache.commons.lang3.StringUtils;
+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.df1.connection.SerialDf1Connection;
+import org.apache.plc4x.java.spi.PlcDriver;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DF1PlcDriver implements PlcDriver {
+
+    public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("tcp://(?<host>[\\w.]+)(:(?<port>\\d*))?");
+    public static final Pattern SERIAL_PATTERN = Pattern.compile("serial://(?<serialDefinition>((?!/\\d).)*)");
+    public static final Pattern DF1_URI_PATTERN = Pattern.compile("^df1:(" + INET_ADDRESS_PATTERN + "|" + SERIAL_PATTERN + ")/?" + "(?<params>\\?.*)?");
+
+    @Override
+    public String getProtocolCode() {
+        return "df1";
+    }
+
+    @Override
+    public String getProtocolName() {
+        return "Allen-Bradley DF1";
+    }
+
+    @Override
+    public PlcConnection connect(String url) throws PlcConnectionException {
+        Matcher matcher = DF1_URI_PATTERN.matcher(url);
+        if (!matcher.matches()) {
+            throw new PlcConnectionException(
+                "Connection url doesn't match the format 'df1:{type}//{port|host}'");
+        }
+
+        String host = matcher.group("host");
+        String serialDefinition = matcher.group("serialDefinition");
+        String portString = matcher.group("port");
+        Integer port = StringUtils.isNotBlank(portString) ? Integer.parseInt(portString) : null;
+        String params = matcher.group("params") != null ? matcher.group("params").substring(1) : null;
+
+        if (serialDefinition != null) {
+            return new SerialDf1Connection(serialDefinition, params);
+        } else {
+            throw new PlcConnectionException("TCP DF1 connections not implemented yet.");
+        }
+    }
+
+    @Override
+    public PlcConnection connect(String url, PlcAuthentication authentication) throws PlcConnectionException {
+        throw new PlcConnectionException("DF1 connections don't support authentication.");
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/BaseDf1Connection.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/BaseDf1Connection.java
new file mode 100644
index 0000000..6f09c02
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/BaseDf1Connection.java
@@ -0,0 +1,34 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+package org.apache.plc4x.java.df1.connection;
+
+import org.apache.plc4x.java.base.connection.ChannelFactory;
+import org.apache.plc4x.java.base.connection.NettyPlcConnection;
+
+public abstract class BaseDf1Connection extends NettyPlcConnection {
+
+    public BaseDf1Connection(ChannelFactory channelFactory) {
+        super(channelFactory);
+    }
+
+    public BaseDf1Connection(ChannelFactory channelFactory, boolean awaitSessionSetupComplete) {
+        super(channelFactory, awaitSessionSetupComplete);
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/SerialDf1Connection.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/SerialDf1Connection.java
new file mode 100644
index 0000000..de8803e
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/connection/SerialDf1Connection.java
@@ -0,0 +1,112 @@
+/*
+ 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.java.df1.connection;
+
+import io.netty.channel.*;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcWriteResponse;
+import org.apache.plc4x.java.base.connection.SerialChannelFactory;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.*;
+import org.apache.plc4x.java.df1.protocol.Df1Protocol;
+import org.apache.plc4x.java.df1.protocol.Plc4XDf1Protocol;
+import org.apache.plc4x.java.df1.util.Df1FieldHandler;
+
+import java.util.concurrent.CompletableFuture;
+
+public class SerialDf1Connection extends BaseDf1Connection implements PlcReader, PlcWriter {
+
+    public SerialDf1Connection(String comPortName, String params) {
+        super(new SerialChannelFactory(comPortName));
+    }
+
+    @Override
+    public boolean canRead() {
+        return true;
+    }
+
+    @Override
+    public boolean canWrite() {
+        return true;
+    }
+
+    @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 Df1Protocol());
+                pipeline.addLast(new Plc4XDf1Protocol());
+            }
+        };
+    }
+
+    @Override
+    public PlcReadRequest.Builder readRequestBuilder() {
+        return new DefaultPlcReadRequest.Builder(this, new Df1FieldHandler());
+    }
+
+    @Override
+    public PlcWriteRequest.Builder writeRequestBuilder() {
+        return new DefaultPlcWriteRequest.Builder(this, new Df1FieldHandler());
+    }
+
+    @Override
+    public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+        CompletableFuture<InternalPlcReadResponse> future = new CompletableFuture<>();
+        PlcRequestContainer<InternalPlcReadRequest, InternalPlcReadResponse> container =
+            new PlcRequestContainer<>((InternalPlcReadRequest) readRequest, future);
+        channel.writeAndFlush(container).addListener(f -> {
+            if (!f.isSuccess()) {
+                future.completeExceptionally(f.cause());
+            }
+        });
+        return future
+            .thenApply(PlcReadResponse.class::cast);
+    }
+
+    @Override
+    public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
+        CompletableFuture<InternalPlcWriteResponse> future = new CompletableFuture<>();
+        PlcRequestContainer<InternalPlcWriteRequest, InternalPlcWriteResponse> container =
+            new PlcRequestContainer<>((InternalPlcWriteRequest) writeRequest, future);
+        channel.writeAndFlush(container).addListener(f -> {
+            if (!f.isSuccess()) {
+                future.completeExceptionally(f.cause());
+            }
+        });
+        return future
+            .thenApply(PlcWriteResponse.class::cast);
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/fields/DataType.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/fields/DataType.java
new file mode 100644
index 0000000..83322f7
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/fields/DataType.java
@@ -0,0 +1,17 @@
+package org.apache.plc4x.java.df1.fields;
+
+public enum DataType {
+
+    BIT,
+    BIT_STRING,
+    BYTE_STRING,
+    INTEGER,
+    TIMER,
+    COUNTER,
+    GENERAL_COUNT_STRUCTURE,
+    FLOAT,
+    ARRAY,
+    ADDRESS,
+    BINARY_CODED_DECIMAL
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java
new file mode 100644
index 0000000..bbeece2
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Df1Protocol.java
@@ -0,0 +1,143 @@
+/*
+ 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.java.df1.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
+import org.apache.plc4x.java.base.PlcByteToMessageCodec;
+import org.apache.plc4x.java.df1.DF1ReadRequest;
+import org.apache.plc4x.java.df1.DF1Symbol;
+import org.apache.plc4x.java.df1.DF1SymbolMessageFrameStart;
+import org.apache.plc4x.java.df1.io.DF1SymbolIO;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Df1Protocol extends PlcByteToMessageCodec<DF1Symbol> {
+
+    private static final Logger logger = LoggerFactory.getLogger(Df1Protocol.class);
+
+    private final DF1SymbolIO df1SymbolIO;
+
+    private Map<Integer, Short> readRequestSizes;
+
+    public Df1Protocol() {
+        df1SymbolIO = new DF1SymbolIO();
+        readRequestSizes = new HashMap<>();
+    }
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, DF1Symbol msg, ByteBuf out) throws Exception {
+        // Remember the size of the request as we need this to decode the response.
+        if(msg instanceof DF1SymbolMessageFrameStart) {
+            DF1SymbolMessageFrameStart frameStart = (DF1SymbolMessageFrameStart) msg;
+            if(frameStart.getCommand() instanceof DF1ReadRequest) {
+                DF1ReadRequest readRequest = (DF1ReadRequest) frameStart.getCommand();
+                int transactionCounter = readRequest.getTransactionCounter();
+                readRequestSizes.put(transactionCounter, readRequest.getSize());
+            }
+        }
+
+        // Serialize the message
+        // TODO: Create the buffer with the correct size.
+        WriteBuffer writeBuffer = new WriteBuffer(100);
+        df1SymbolIO.serialize(writeBuffer, msg);
+        byte[] data = writeBuffer.getData();
+
+        // Send the serialized data
+        out.writeBytes(data);
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+        short size = 0x00;
+
+        // Yes, it's a little complicated, but we need to find out if we've got enough data.
+        if(in.readableBytes() > 2) {
+            if(in.getUnsignedByte(0) != (short) 0x10) {
+                logger.warn("Expecting DF1 magic number: {}", 0x10);
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Got Data: {}", ByteBufUtil.hexDump(in));
+                }
+                exceptionCaught(ctx, new PlcProtocolException(
+                    String.format("Expecting DF1 magic number: %02X", 0x10)));
+                return;
+            }
+
+            short symbolType = in.getUnsignedByte(1);
+            switch (symbolType) {
+                case (short) 0x02: {
+                    if(in.readableBytes() < 5) {
+                        return;
+                    }
+                    short commandType = in.getUnsignedByte(4);
+                    switch (commandType) {
+                        case (short) 0x01: {
+                            if(in.readableBytes() < 11) {
+                                return;
+                            }
+                            break;
+                        }
+                        case (short) 0x41: {
+                            int transactionCounter = in.getUnsignedShort(6);
+                            if(!readRequestSizes.containsKey(transactionCounter)) {
+                                logger.warn("Unknown transaction counter: {}", transactionCounter);
+                                if (logger.isDebugEnabled()) {
+                                    logger.debug("Got Data: {}", ByteBufUtil.hexDump(in));
+                                }
+                                exceptionCaught(ctx, new PlcProtocolException(
+                                    String.format("Unknown transaction counte: %04X", transactionCounter)));
+                                return;
+                            }
+                            size = readRequestSizes.remove(transactionCounter);
+                            if(in.readableBytes() < 8 + size) {
+                                return;
+                            }
+                            break;
+                        }
+                    }
+                    break;
+                }
+                case (short) 0x03: {
+                    if(in.readableBytes() < 4) {
+                        return;
+                    }
+                    break;
+                }
+            }
+        }
+
+        // Parse the message received from the DF1 device
+        byte[] data = new byte[in.readableBytes()];
+        in.readBytes(data);
+        ReadBuffer readBuffer = new ReadBuffer(data);
+        DF1Symbol resp = df1SymbolIO.parse(readBuffer, size);
+
+        // Add the received message to the output
+        out.add(resp);
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java
new file mode 100644
index 0000000..9a35c53
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/protocol/Plc4XDf1Protocol.java
@@ -0,0 +1,40 @@
+/*
+ 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.java.df1.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.java.df1.DF1Symbol;
+
+import java.util.List;
+
+public class Plc4XDf1Protocol extends PlcMessageToMessageCodec<DF1Symbol, PlcRequestContainer> {
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception {
+
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, DF1Symbol msg, List<Object> out) throws Exception {
+
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/Df1FieldHandler.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/Df1FieldHandler.java
new file mode 100644
index 0000000..52e8bfc
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/Df1FieldHandler.java
@@ -0,0 +1,38 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+package org.apache.plc4x.java.df1.util;
+
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
+
+public class Df1FieldHandler extends DefaultPlcFieldHandler {
+
+    @Override
+    public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+        return null;
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeByte(PlcField field, Object[] values) {
+        return super.encodeByte(field, values);
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java
deleted file mode 100644
index cc292fa..0000000
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.protocol.df1;
-
-import com.fazecast.jSerialComm.SerialPort;
-import org.apache.commons.codec.binary.Hex;
-//import org.apache.plc4x.java.df1.TPKTPacket;
-//import org.apache.plc4x.java.df1.io.TPKTPacketIO;
-import org.apache.plc4x.java.df1.DF1Command;
-import org.apache.plc4x.java.df1.DF1SymbolMessageFrameStart;
-import org.apache.plc4x.java.utils.ReadBuffer;
-import org.apache.plc4x.java.utils.WriteBuffer;
-import org.apache.plc4x.java.df1.DF1Symbol;
-import org.apache.plc4x.java.df1.io.DF1SymbolIO;
-import purejavacomm.CommPortIdentifier;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.BitSet;
-
-public class BenchmarkGeneratedDf1 {
-
-    public static void main(String[] args) throws Exception {
-//        byte[] rData = Hex.decodeHex("0300006702f080320100000001005600000407120a10060001032b84000160120a10020001032b840001a0120a10010001032b840001a9120a10050001032b84000150120a10020001032b84000198120a10040001032b84000140120a10020001032b84000190");
-//        long start = System.currentTimeMillis();
-//        int numRunsParse = 2000000;
-//        TPKTPacketIO tpktPacketIO = new TPKTPacketIO();
-//
-//
-//        CommPortIdentifier id = CommPortIdentifier.getPortIdentifier("");
-//
-//
-//        // Benchmark the parsing code
-//        TPKTPacket packet = null;
-//        for(int i = 0; i < numRunsParse; i++) {
-//            ReadBuffer rBuf = new ReadBuffer(rData);
-//            packet = tpktPacketIO.parse(rBuf);
-//        }
-//        long endParsing = System.currentTimeMillis();
-//
-//        System.out.println("Parsed " + numRunsParse + " packets in " + (endParsing - start) + "ms");
-//        System.out.println("That's " + ((float) (endParsing - start) / numRunsParse) + "ms per packet");
-//
-//        // Benchmark the serializing code
-//        int numRunsSerialize = 2000000;
-//        byte[] oData = null;
-//        for(int i = 0; i < numRunsSerialize; i++) {
-//            WriteBuffer wBuf = new WriteBuffer(packet.getLengthInBytes());
-//            tpktPacketIO.serialize(wBuf, packet);
-//            oData = wBuf.getData();
-//        }
-//        long endSerializing = System.currentTimeMillis();
-//
-//        System.out.println("Serialized " + numRunsSerialize + " packets in " + (endSerializing - endParsing) + "ms");
-//        System.out.println("That's " + ((float) (endSerializing - endParsing) / numRunsSerialize) + "ms per packet");
-//        if(!Arrays.equals(rData, oData)) {
-//            for(int i = 0; i < rData.length; i++) {
-//                if(rData[i] != oData[i]) {
-//                    System.out.println("Difference in byte " + i);
-//                }
-//            }
-//            System.out.println("Not equals");
-//        } else {
-//            System.out.println("Bytes equal");
-//        }
-
-
-        byte[] rData = {0x10, 0x02, 0x00, 0x09, 0x41, 0x00, 0x01, 0x00, 0x1F, 0x1F, 0x10, 0x03, 0x1A, 0x2B};
-
-        DF1SymbolIO df1SymbolIO = new DF1SymbolIO();
-        DF1Symbol packet;
-        ReadBuffer rBuf = new ReadBuffer(rData);
-        int statusWord = (rData[7]<<8) + rData[6];
-        DF1Command messageCommand = new DF1Command((short)rData[5]); //,(short)statusWord);
-        DF1SymbolMessageFrameStart messageStart = new DF1SymbolMessageFrameStart((short)rData[3],(short)rData[2], messageCommand);
-        packet = df1SymbolIO.parse(rBuf, (short) (rData.length-12), messageStart);
-
-        System.out.println("x: " + packet);
-        System.exit(0);
-
-
-
-        SerialPort comPort = SerialPort.getCommPorts()[0];
-        comPort.openPort();
-
-        comPort.setComPortParameters(19200, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
-//        comPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 0, 0);
-
-        System.out.print(comPort.getSystemPortName() + " | ");
-        System.out.print(comPort.getPortDescription() + " | ");
-        System.out.print(comPort.getDescriptivePortName() + " | Baud rate: ");
-        System.out.println(comPort.getBaudRate());
-//        System.out.println(comPort.getReadTimeout());
-//        System.out.println(comPort.getWriteTimeout());
-
-
-        DF1SymbolIO df1message = new DF1SymbolIO();
-
-
-        byte[] c_STX = {0x02};
-        byte[] c_SOH = {0x01};
-        byte[] c_ETX = {0x03};
-        byte[] c_EOT = {0x04};
-        byte[] c_ENQ = {0x05};
-        byte[] c_ACK = {0x06};
-        byte[] c_DLE = {0x10};
-        byte[] c_NAK = {0x0f};
-
-        byte[] c_DST = {0x09};
-        byte[] c_SRC = {0x00};
-        byte[] c_CMD = {0x06};
-        byte[] c_FNC = {0x03};
-        byte[] c_STS = {0x00};
-        byte[] c_TNS = {0x01, 0x00};
-        byte[] c_ADR = {0x11, 0x00};
-        byte[] c_SZE = {0x02};
-//        byte[] c_BCC = {-30};
-
-//        byte[] c_STN = {0x11};
-//        byte[] c_DST = {0x01};
-//        byte[] c_SRC = {0x00};
-//        byte[] c_SZE = {0x0c};
-//        byte[] c_TNS = {0x41, 0x00};
-//        byte[] c_ADR = {0x12, 0x00};
-//        byte[] c_CRC = {-49, 0x40};
-
-
-//        byte[] message = {0x10, 0x01, 0x11, 0x10, 0x02, 0x09, 0x00, 0x01, 0x00, 0x41, 0x00, 0x12, 0x00, 0x0c, 0x10, 0x03}; // halfduplex msg
-//        comPort.writeBytes(message, message.length);
-
-//        byte[] message = {0x10, 0x05, 0x11, -17};         // halfduplex poll
-//        comPort.writeBytes(message, message.length);
-
-
-        comPort.writeBytes(c_DLE, 1);     // fullduplex msg Seite 235
-        comPort.writeBytes(c_STX, 1);
-        comPort.writeBytes(c_DST, 1);
-        comPort.writeBytes(c_SRC, 1);
-        comPort.writeBytes(c_CMD, 1);
-        comPort.writeBytes(c_STS, 1);
-        comPort.writeBytes(c_TNS, 2);
-        comPort.writeBytes(c_FNC, 1);
-//        comPort.writeBytes(c_ADR, 2);
-//        comPort.writeBytes(c_SZE, 1);
-        comPort.writeBytes(c_DLE, 1);
-        comPort.writeBytes(c_ETX, 1);
-
-
-//        int[] crcmsg = {c_DST[0], c_SRC[0], c_CMD[0], c_STS[0], c_TNS[0], c_TNS[1], c_ADR[0], c_ADR[1], c_SZE[0], c_ETX[0]}; // fullduplex CRC
-        int[] crcmsg = {c_DST[0], c_SRC[0], c_CMD[0], c_STS[0], c_TNS[0], c_TNS[1], c_FNC[0], c_ETX[0]};                       // diagnostic status request
-//        int[] crcmsg = {0x11, 0x02, 0x09, 0x00, 0x01, 0x00, 0x41, 0x00, 0x12, 0x00, 0x0c, 0x03}; // halfduplex CRC
-
-        int[] c_CRC = CalcCRC(crcmsg);
-        byte[] crc1 = {(byte)c_CRC[0]};
-        byte[] crc2 = {(byte)c_CRC[1]};
-        comPort.writeBytes(crc1, 1);
-        comPort.writeBytes(crc2, 1);
-
-
-        while (comPort.bytesAvailable() == 0) {
-            Thread.sleep(22); }
-
-        byte[] readBuffer = new byte[comPort.bytesAvailable()];
-        int numRead = comPort.readBytes(readBuffer, readBuffer.length);
-        System.out.println("Read " + numRead + " bytes.");
-
-        for (byte c_RCV : readBuffer) {
-            System.out.print(Integer.toHexString(c_RCV) + " | "); }
-        System.out.println("");
-
-//        if (numRead > 1) {
-//            if (readBuffer[1] != 0x15) {
-//                comPort.writeBytes(c_DLE, 1);
-//                comPort.writeBytes(c_ACK, 1);
-//            }
-//        }
-
-        while (comPort.bytesAvailable() == 0) {
-            Thread.sleep(22); }
-
-
-        byte[] readBuffer2 = new byte[comPort.bytesAvailable()];
-        int numRead2 = comPort.readBytes(readBuffer2, readBuffer2.length);
-        System.out.println("Read " + numRead2 + " bytes.");
-
-        for (byte c_RCV2 : readBuffer2) {
-            System.out.print(Integer.toHexString(c_RCV2) + " | "); }
-        System.out.println("");
-
-        comPort.closePort();
-
-    }
-
-        private static int[] CalcCRC(int[] crcBytes) {
-            int tmp = 0;
-            int crcL, crcR;
-
-            for (int newByte : crcBytes ) {
-                crcL = tmp >> 8;
-                crcR = tmp & 0xFF;
-                tmp = (crcL << 8) + (newByte ^ crcR);
-                for (int j=0; j<8; j++)
-                    if (tmp % 2 == 1) {     // check if LSB shifted out is 1 or 0
-                        tmp = tmp >> 1;
-                        tmp = tmp ^ 0xA001;
-                    } else {
-                        tmp = tmp >> 1;
-                    }
-            }
-
-//            return ((tmp & 0xFF) << 8) + (tmp >> 8);  // returns lowbyte|highbyte as one number, change return to non-array
-
-            int[] tmparray = {(tmp & 0xFF), (tmp >> 8)};
-            return tmparray;
-        }
-
-        private static int CalcBCC(int[] crcBytes) {
-            int tmp = 0;
-            int j = 0;
-
-            for (int newByte : crcBytes) {
-                tmp = tmp + newByte;
-                if (newByte == 0x10) {
-                    j = ++j; }
-            }
-            tmp = tmp - ((j/2) * 0x10);  // get rid of double DLE
-            return ((~tmp) & 0b11111111) + 1;
-        }
-}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/DF1Utils.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/DF1Utils.java
index d605293..a85ab8f 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/DF1Utils.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/DF1Utils.java
@@ -16,13 +16,69 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.plc4x.protocol.df1;
 
+import org.apache.plc4x.java.df1.DF1ReadRequest;
+import org.apache.plc4x.java.df1.DF1Symbol;
+import org.apache.plc4x.java.df1.DF1SymbolMessageFrameStart;
+import org.apache.plc4x.java.utils.ParseException;
+import org.apache.plc4x.java.utils.WriteBuffer;
 
-package org.apache.plc4x.protocol.df1;
+import java.nio.ByteBuffer;
 
 public class DF1Utils {
 
     public static short CRCCheck(Object... args) {
+        DF1Symbol symbol = (DF1Symbol) args[1];
+        short messageType = (short) args[0];
+        if(symbol instanceof DF1SymbolMessageFrameStart) {
+            DF1SymbolMessageFrameStart messageFrameStart = (DF1SymbolMessageFrameStart) symbol;
+
+            short destinationAddress = messageFrameStart.getDestinationAddress();
+            short sourceAddress = messageFrameStart.getSourceAddress();
+            short commandDiscriminatorValues = (short) messageFrameStart.getCommand().getDiscriminatorValues()[0];
+            short status = messageFrameStart.getCommand().getStatus();
+            int   counter = messageFrameStart.getCommand().getTransactionCounter();
+            if(messageFrameStart.getCommand() instanceof DF1ReadRequest) {
+                DF1ReadRequest readRequestCommand = (DF1ReadRequest) messageFrameStart.getCommand();
+
+                try {
+                    WriteBuffer writeBuffer = new WriteBuffer(10, false);
+                    writeBuffer.writeUnsignedShort(8, destinationAddress);
+                    writeBuffer.writeUnsignedShort(8, sourceAddress);
+                    writeBuffer.writeUnsignedShort(8, commandDiscriminatorValues);
+                    writeBuffer.writeUnsignedShort(8, status);
+                    writeBuffer.writeUnsignedInt(16, (short) counter);
+                    writeBuffer.writeUnsignedInt(16, (short) readRequestCommand.getAddress());
+                    writeBuffer.writeUnsignedShort(8, (byte) readRequestCommand.getSize());
+                    writeBuffer.writeUnsignedShort(8, (byte) messageType);
+
+                    byte[] data = writeBuffer.getData();
+
+                    int tmp = 0;
+                    int crcL, crcR;
+
+                    for (int newByte : data) {
+                        crcL = tmp >> 8;
+                        crcR = tmp & 0xFF;
+                        tmp = (crcL << 8) + (newByte ^ crcR);
+                        for (int j=0; j<8; j++)
+                            if (tmp % 2 == 1) {     // check if LSB shifted out is 1 or 0
+                                tmp = tmp >> 1;
+                                tmp = tmp ^ 0xA001;
+                            } else {
+                                tmp = tmp >> 1;
+                            }
+                    }
+
+                    return (short) tmp;
+                } catch (ParseException e) {
+                    throw new RuntimeException("Something wen't wrong during the CRC check", e);
+                }
+            }
+        }
+
         return 0;
     }
+
 }
diff --git a/sandbox/test-java-df1-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-df1-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
new file mode 100644
index 0000000..fddc33d
--- /dev/null
+++ b/sandbox/test-java-df1-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.java.df1.DF1PlcDriver
diff --git a/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java
new file mode 100644
index 0000000..e092cb6
--- /dev/null
+++ b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkGeneratedDf1.java
@@ -0,0 +1,84 @@
+/*
+ * 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.protocol.df1;
+
+import com.fazecast.jSerialComm.SerialPort;
+import org.apache.plc4x.java.df1.*;
+import org.apache.plc4x.java.df1.io.ReadRequestIO;
+import org.apache.plc4x.java.df1.io.ReadResponseIO;
+import org.apache.plc4x.java.df1.io.ResultIO;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+
+public class BenchmarkGeneratedDf1 {
+
+    public static void main(String[] args) throws Exception {
+        // Manually build a message
+        ReadRequest readRequest = new ReadRequest(new DF1SymbolMessageFrameStart((short) 0x09, (short) 0x00, new DF1ReadRequest((short) 0x00, 0x01, 0x0B, (short) 0x02)), new DF1SymbolMessageFrameEnd());
+
+        // Serialize the message
+        WriteBuffer writeBuffer = new WriteBuffer(100, false);
+        new ReadRequestIO().serialize(writeBuffer, readRequest);
+        byte[] data = writeBuffer.getData();
+
+        // Send the serialized message to the PLC via COM port
+        SerialPort comPort = SerialPort.getCommPort("/dev/cu.usbserial-AL065SUZ");
+        comPort.openPort();
+        comPort.setComPortParameters(19200, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
+        comPort.writeBytes(data, 20);
+
+        // Give the PLC some time to respond.
+        while (comPort.bytesAvailable() == 0) {
+            Thread.sleep(22);
+        }
+
+        // Read the response
+        byte[] readBytes = new byte[comPort.bytesAvailable()];
+        comPort.readBytes(readBytes, readBytes.length);
+
+        // Parse the ACK/NACK response
+        ReadBuffer readBuffer = new ReadBuffer(readBytes);
+        Result result = new ResultIO().parse(readBuffer);
+
+        // Check if the response was an ACK
+        if(result.getResult() instanceof DF1SymbolMessageFrameACK) {
+            // The actual result is sent with a little delay.
+            while (comPort.bytesAvailable() == 0) {
+                Thread.sleep(22);
+            }
+
+            // Read the actual response data
+            readBytes = new byte[comPort.bytesAvailable()];
+            comPort.readBytes(readBytes, readBytes.length);
+
+            // Parse the response
+            readBuffer = new ReadBuffer(readBytes);
+            ReadResponse readResponse = new ReadResponseIO().parse(readBuffer, (short) 0x02);
+
+            // So something senseless ;-)
+            System.out.println(readResponse);
+        } else {
+            System.out.println("Didn't get an ACK");
+        }
+
+        comPort.closePort();
+    }
+
+}
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
similarity index 99%
rename from sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
rename to sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
index 5fa447e..c2571fe 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
+++ b/sandbox/test-java-df1-driver/src/test/java/org/apache/plc4x/protocol/df1/BenchmarkManualDf1.java
@@ -78,7 +78,7 @@ public class BenchmarkManualDf1 {
 
         byte[] rData = {0x10, 0x02, 0x00, 0x09, 0x41, 0x00, 0x01, 0x00, 0x1F, 0x1F, 0x10, 0x03, 0x1A, 0x2B};
 
-        DF1SymbolIO df1SymbolIO = new DF1SymbolIO();
+ /*       DF1SymbolIO df1SymbolIO = new DF1SymbolIO();
         DF1Symbol packet;
         ReadBuffer rBuf = new ReadBuffer(rData);
         int statusWord = (rData[7]<<8) + rData[6];
@@ -198,7 +198,7 @@ public class BenchmarkManualDf1 {
             System.out.print(Integer.toHexString(c_RCV2) + " | "); }
         System.out.println("");
 
-        comPort.closePort();
+        comPort.closePort();*/
 
     }