You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2019/11/28 11:03:26 UTC

[plc4x] 01/01: initial ams/ads mspec

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

sruehl pushed a commit to branch feature/ams_ads_mpsec
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 3ed19c6c696955c7a8b597f97b6fdd6a603d8ec6
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Thu Nov 28 12:02:54 2019 +0100

    initial ams/ads mspec
---
 protocols/amsads/pom.xml                           |  43 ++++
 .../plc4x/protocol/amsads/AMSADSProtocol.java      |  47 ++++
 ...e.plc4x.plugins.codegenerator.protocol.Protocol |  38 ++++
 .../main/resources/protocols/amsads/amsads.mspec   |  80 +++++++
 protocols/pom.xml                                  |   1 +
 sandbox/pom.xml                                    |   1 +
 sandbox/test-java-amsads-driver/README.adoc        |  35 +++
 sandbox/test-java-amsads-driver/pom.xml            | 171 +++++++++++++++
 .../apache/plc4x/java/amsads/AMSADSPlcDriver.java  |  74 +++++++
 .../org/apache/plc4x/java/amsads/Df1Field.java     |  62 ++++++
 .../amsads/connection/BaseAMSADSConnection.java    |  34 +++
 .../amsads/connection/SerialAMSADSConnection.java  | 148 +++++++++++++
 .../apache/plc4x/java/amsads/fields/DataType.java  |  44 ++++
 .../plc4x/java/amsads/protocol/AMSADSProtocol.java | 157 ++++++++++++++
 .../java/amsads/protocol/Plc4XDf1Protocol.java     | 172 +++++++++++++++
 .../apache/plc4x/java/amsads/util/DF1Utils.java    | 158 ++++++++++++++
 .../plc4x/java/amsads/util/Df1FieldHandler.java    |  39 ++++
 .../services/org.apache.plc4x.java.spi.PlcDriver   |  38 ++++
 .../plc4x/java/amsads/AMSADSPlcDriverTest.java     |  44 ++++
 .../protocol/amsads/BenchmarkGeneratedDf1.java     |  81 +++++++
 .../plc4x/protocol/amsads/BenchmarkManualDf1.java  | 239 +++++++++++++++++++++
 .../org/apache/plc4x/protocol/amsads/Df1Test.java  |  30 +++
 .../apache/plc4x/protocol/amsads/EndToEndTest.java |  56 +++++
 .../org/apache/plc4x/protocol/amsads/IOTest.java   |  99 +++++++++
 .../src/test/resources/testsuite/Df1Testsuite.xml  | 101 +++++++++
 25 files changed, 1992 insertions(+)

diff --git a/protocols/amsads/pom.xml b/protocols/amsads/pom.xml
new file mode 100644
index 0000000..f48b8b5
--- /dev/null
+++ b/protocols/amsads/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x</groupId>
+    <artifactId>plc4x-protocols</artifactId>
+    <version>0.6.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>plc4x-protocols-amsads</artifactId>
+
+  <name>Protocols: AMS/ADS</name>
+  <description>Base protocol specifications for the AMS/ADS protocol</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-build-utils-protocol-base-mspec</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/protocols/amsads/src/main/java/org/apache/plc4x/protocol/amsads/AMSADSProtocol.java b/protocols/amsads/src/main/java/org/apache/plc4x/protocol/amsads/AMSADSProtocol.java
new file mode 100644
index 0000000..0d872a6
--- /dev/null
+++ b/protocols/amsads/src/main/java/org/apache/plc4x/protocol/amsads/AMSADSProtocol.java
@@ -0,0 +1,47 @@
+/*
+ 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.amsads;
+
+import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class AMSADSProtocol implements Protocol {
+
+    @Override
+    public String getName() {
+        return "amsads";
+    }
+
+    @Override
+    public Map<String, TypeDefinition> getTypeDefinitions() throws GenerationException {
+        InputStream schemaInputStream = AMSADSProtocol.class.getResourceAsStream("/protocols/amsads/amsads.mspec");
+        if(schemaInputStream == null) {
+            throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
+        }
+        return new MessageFormatParser().parse(schemaInputStream);
+    }
+
+}
diff --git a/protocols/amsads/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol b/protocols/amsads/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000..9d1f50e
--- /dev/null
+++ b/protocols/amsads/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.plc4x.protocol.amsads.AMSADSProtocol
\ No newline at end of file
diff --git a/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec b/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec
new file mode 100644
index 0000000..0cc973f
--- /dev/null
+++ b/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec
@@ -0,0 +1,80 @@
+//
+// 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.
+//
+
+////////////////////////////////////////////////////////////////
+// AMS/TCP Paket
+////////////////////////////////////////////////////////////////
+
+[type 'AMSPacket'
+    [reserved   uint       16   '0x0000'                                      ]
+    [implicit   uint       32   'header.lengthInBytes + data.lengthInBytes'   ]
+    [simple     AMSHeader  'header'                                           ]
+    [simple     ADSData    'data'                                             ]
+]
+
+[type 'AMSHeader'
+    [simple     AMSNetId        'targetAmsNetId'    ]
+    [simple     uint        16  'targetAmsPort'     ]
+    [simple     AMSNetId        'sourceAmsNetId'    ]
+    [simple     uint        16  'sourceAmsPort'     ]
+    [enum       CommandId       'commandId'         ]
+    [bitmask    State           'state'             ]
+    [simple     uint        32  '../data.lengthInBytes'        ]
+    [simple     uint        32  'errorCode']
+    [simple     byte        32  'invokeId'          ]
+]
+
+[enum uint 16 'CommandId'
+    ['0x00' INVALID]
+    ['0x01' ADS_READ_DEVICE_INFO]
+    ['0x02' ADS_READ]
+    ['0x03' ADS_WRITE]
+    ['0x04' ADS_READ_STATE]
+    ['0x05' ADS_WRITE_CONTROL]
+    ['0x06' ADS_ADD_DEVICE_NOTIFICATION]
+    ['0x07' ADS_DELETE_DEVICE_NOTIFICATION]
+    ['0x08' ADS_DEVICE_NOTIFICATION]
+    ['0x09' ADS_READ_WRITE]
+]
+
+[bitmask byte 2 'State'
+    ['0b0000_0000_0000_0001' RESPONSE]
+    ['0b0000_0000_0000_0010' NO_RETURN]
+    ['0b0000_0000_0000_0100' ADS_COMMAND]
+    ['0b0000_0000_0000_1000' SYSTEM_COMMAND]
+    ['0b0000_0000_0001_0000' HIGH_PRIORITY_COMMAND]
+    ['0b0000_0000_0010_0000' TIMESTAMP_ADDED]
+    ['0b0000_0000_0100_0000' UDP_COMMAND]
+    ['0b0000_0000_1000_0000' INIT_COMMAND]
+    ['0b1000_0000_0000_0000' BROADCAST]
+]
+
+[type 'AMSNetId'
+    [simple     uint        8   'octet1'            ]
+    [simple     uint        8   'octet2'            ]
+    [simple     uint        8   'octet3'            ]
+    [simple     uint        8   'octet4'            ]
+    [simple     uint        8   'octet5'            ]
+    [simple     uint        8   'octet6'            ]
+]
+
+[type 'ADSData'
+   // TODO: implement me..... arrrrrrrggggggggggggg
+   ....
+]
\ No newline at end of file
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 73d2874..5abb27e 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -190,6 +190,7 @@
   </build>
 
   <modules>
+    <module>amsads</module>
     <module>ab-eth</module>
     <module>bacnetip</module>
     <module>df1</module>
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 600d99c..3173d2e 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -39,6 +39,7 @@
     <module>plc-simulator</module>
     <module>streampipes-connectors</module>
 
+    <module>test-java-amsads-driver</module>
     <module>test-java-bacnetip-driver</module>
     <module>test-java-knxnetip-driver</module>
     <module>test-java-s7-driver</module>
diff --git a/sandbox/test-java-amsads-driver/README.adoc b/sandbox/test-java-amsads-driver/README.adoc
new file mode 100644
index 0000000..4652b54
--- /dev/null
+++ b/sandbox/test-java-amsads-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-amsads-driver</artifactId>
+          <version>0.6.0-SNAPSHOT</version>
+          <scope>runtime</scope>
+        </dependency>
+
+Then start the Hello world (Ideally in IntelliJ) with the following program arguments:
+
+    amsads: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-amsads-driver/pom.xml b/sandbox/test-java-amsads-driver/pom.xml
new file mode 100644
index 0000000..f9efcf5
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/pom.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>plc4x-sandbox</artifactId>
+    <version>0.6.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-java-amsads-driver</artifactId>
+
+  <name>Sandbox: Test Generated AMS/ADS Driver</name>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>test</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>amsads</protocolName>
+              <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-tcp</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-serial</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-driver-base-java</artifactId>
+      <version>0.6.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>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-build-utils-language-java</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+  <!--  &lt;!&ndash; https://mvnrepository.com/artifact/org.rxtx/rxtx &ndash;&gt;
+    <dependency>
+      <groupId>org.rxtx</groupId>
+      <artifactId>rxtx</artifactId>
+      <version>2.1.7</version>
+    </dependency>-->
+
+    <dependency>
+      <groupId>com.github.purejavacomm</groupId>
+      <artifactId>purejavacomm</artifactId>
+      <version>1.0.2.RELEASE</version>
+    </dependency>
+
+    <!-- Logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+      <version>1.7.25</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-amsads</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-protocol-test-utils</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-xml</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.platform</groupId>
+      <artifactId>junit-platform-launcher</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+</project>
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java
new file mode 100644
index 0000000..34b584f
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/AMSADSPlcDriver.java
@@ -0,0 +1,74 @@
+/*
+ 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.amsads;
+
+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 AMSADSPlcDriver implements PlcDriver {
+
+    // TODO there is only serial, I guess?
+    public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("tcp://(?<host>[\\w.]+)(:(?<port>\\d*))?");
+    public static final Pattern SERIAL_PATTERN = Pattern.compile("serial://(?<serialDefinition>/?[a-zA-Z0-9/]*)");
+    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 doesn't support authentication.");
+    }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/Df1Field.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/Df1Field.java
new file mode 100644
index 0000000..762425a
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/Df1Field.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.java.amsads;
+
+import com.sun.jna.StringArray;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.df1.fields.DataType;
+
+public class Df1Field implements PlcField {
+
+    private final int address;
+    private final int size;
+    private final DataType dataType;
+    private final addressType address_type;
+
+    public Df1Field(int address, int size, DataType dataType, addressType address_type) {
+        this.address = address;
+        this.size = size;
+        this.dataType = dataType;
+        this.address_type = address_type;
+    }
+
+    public int getAddress() {
+        return address;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public DataType getDataType() {
+        return dataType;
+    }
+
+    public addressType getAddress_type() { return address_type; }
+
+    public static PlcField of(String fieldQuery) {
+        String[] tmp = fieldQuery.split(":");
+        return new Df1Field(Integer.parseInt(tmp[0]), DataType.valueOf(tmp[1]).getLength(),DataType.valueOf(tmp[1]), addressType.OFFSET);
+    }
+
+    public enum addressType {
+        OFFSET,
+        LOGICAL
+    }
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/BaseAMSADSConnection.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/BaseAMSADSConnection.java
new file mode 100644
index 0000000..f1bdf79
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/BaseAMSADSConnection.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.amsads.connection;
+
+import org.apache.plc4x.java.base.connection.ChannelFactory;
+import org.apache.plc4x.java.base.connection.NettyPlcConnection;
+
+public abstract class BaseAMSADSConnection extends NettyPlcConnection {
+
+    public BaseAMSADSConnection(ChannelFactory channelFactory) {
+        super(channelFactory);
+    }
+
+    public BaseAMSADSConnection(ChannelFactory channelFactory, boolean awaitSessionSetupComplete) {
+        super(channelFactory, awaitSessionSetupComplete);
+    }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/SerialAMSADSConnection.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/SerialAMSADSConnection.java
new file mode 100644
index 0000000..4eded14
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/connection/SerialAMSADSConnection.java
@@ -0,0 +1,148 @@
+/*
+ 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.amsads.connection;
+
+import io.netty.channel.*;
+import org.apache.commons.lang3.StringUtils;
+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.ChannelFactory;
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.CompletableFuture;
+
+public class SerialAMSADSConnection extends BaseAMSADSConnection implements PlcReader, PlcWriter {
+
+    private static final Logger logger = LoggerFactory.getLogger(SerialAMSADSConnection.class);
+
+    private short localAddr;
+    private short remoteAddr;
+
+    public SerialAMSADSConnection(String comPortName, String params) {
+        this(new SerialChannelFactory(comPortName), params);
+    }
+
+    public SerialAMSADSConnection(ChannelFactory channelFactory, String params) {
+        super(channelFactory, false);
+        this.localAddr = (short) 0x00;
+        this.remoteAddr = (short) 0x09;
+
+        // Override some of the settings, if they are asked for.
+        if (!StringUtils.isEmpty(params)) {
+            for (String param : params.split("&")) {
+                String[] paramElements = param.split("=");
+                String paramName = paramElements[0];
+                if (paramElements.length == 2) {
+                    String paramValue = paramElements[1];
+                    switch (paramName) {
+                        case "local-addr":
+                            this.localAddr = Short.parseShort(paramValue);
+                            break;
+                        case "remote-addr":
+                            this.remoteAddr = Short.parseShort(paramValue);
+                            break;
+                        default:
+                            logger.debug("Unknown parameter {} with value {}", paramName, paramValue);
+                    }
+                }
+            }
+        }
+    }
+
+    @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(localAddr, remoteAddr));
+                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-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/fields/DataType.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/fields/DataType.java
new file mode 100644
index 0000000..97b8b17
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/fields/DataType.java
@@ -0,0 +1,44 @@
+/*
+ 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.amsads.fields;
+
+public enum DataType {
+    BIT((short)1),
+    BIT_STRING((short)-1),
+    BYTE_STRING((short)-1),
+    INTEGER((short)2),
+    TIMER((short)-1),
+    COUNTER((short)-1),
+    GENERAL_COUNT_STRUCTURE((short)-1),
+    FLOAT((short)-1),
+    ARRAY((short)-1),
+    ADDRESS((short)-1),
+    BINARY_CODED_DECIMAL((short)-1);
+
+    private final short length;
+
+    DataType(short length) {
+        this.length = length;
+    }
+
+    public short getLength() {
+        return length;
+    }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AMSADSProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AMSADSProtocol.java
new file mode 100644
index 0000000..36aed20
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AMSADSProtocol.java
@@ -0,0 +1,157 @@
+/*
+ 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.readwrite.DF1Command;
+import org.apache.plc4x.java.df1.readwrite.DF1Symbol;
+import org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame;
+import org.apache.plc4x.java.df1.readwrite.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.List;
+
+public class AMSADSProtocol extends PlcByteToMessageCodec<AMSADSCommand> {
+
+    private static final Logger logger = LoggerFactory.getLogger(Df1Protocol.class);
+
+    private final short localAddr;
+    private final short remoteAddr;
+    private final DF1SymbolIO df1SymbolIO;
+
+    public Df1Protocol(short localAddr, short remoteAddr) {
+        this.localAddr = localAddr;
+        this.remoteAddr = remoteAddr;
+        df1SymbolIO = new DF1SymbolIO();
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+    }
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, DF1Command msg, ByteBuf out) throws Exception {
+        // Create a new df1 frame for transmitting the command
+        DF1SymbolMessageFrame frame = new DF1SymbolMessageFrame(remoteAddr, localAddr, msg);
+
+        // Serialize the message
+        WriteBuffer writeBuffer = new WriteBuffer(frame.getLengthInBytes(), false);
+        df1SymbolIO.serialize(writeBuffer, frame);
+        byte[] data = writeBuffer.getData();
+
+        // Send the serialized data
+        // ctx.writeAndFlush(data);
+        out.writeBytes(data);
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+        DF1Symbol resp;
+
+//        do {
+
+            in.markReaderIndex();
+
+            short size = 0x00;
+
+            // Yes, it's a little complicated, but we need to find out if we've got enough data.
+            if (in.readableBytes() > 1) {
+                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;
+                            }*/
+                                // TODO: Let's just assume all is good for now ...
+                                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, false);
+
+            resp = df1SymbolIO.parse(readBuffer);
+
+//        } while (readWasSucessfull);
+//        // TODO if unableto read
+//        in.resetReaderIndex();
+
+        // Add the received message to the output
+        out.add(resp);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        cause.printStackTrace();
+        ctx.close();
+        //super.exceptionCaught(ctx, cause);
+    }
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Plc4XDf1Protocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Plc4XDf1Protocol.java
new file mode 100644
index 0000000..d169dca
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/Plc4XDf1Protocol.java
@@ -0,0 +1,172 @@
+/*
+ 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.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcRequest;
+import org.apache.plc4x.java.api.messages.PlcResponse;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
+import org.apache.plc4x.java.base.messages.DefaultPlcReadResponse;
+import org.apache.plc4x.java.base.messages.InternalPlcReadRequest;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
+import org.apache.plc4x.java.base.messages.items.DefaultIntegerFieldItem;
+import org.apache.plc4x.java.df1.*;
+import org.apache.plc4x.java.df1.readwrite.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Plc4XDf1Protocol extends PlcMessageToMessageCodec<DF1Symbol, PlcRequestContainer> {
+
+    private static final Logger logger = LoggerFactory.getLogger(Plc4XDf1Protocol.class);
+
+    private final AtomicInteger transactionId = new AtomicInteger(1);
+    private Map<Integer, PlcRequestContainer> requests = new ConcurrentHashMap<>();
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception {
+        logger.trace("Received Request {} to send out", msg);
+        if (msg.getRequest() instanceof PlcReadRequest) {
+            for (PlcField field : ((PlcReadRequest) msg.getRequest()).getFields()) {
+                if (!(field instanceof Df1Field)) {
+                    throw new IllegalArgumentException("Invalid field type found inside Df1 Request");
+                }
+                int address = ((Df1Field) field).getAddress();
+                short size = ((Df1Field) field).getDataType().getLength();
+                int transactionId = this.transactionId.getAndIncrement();
+                while (((transactionId & 0xFF) == 0x10) || (((transactionId >>> 8) & 0xFF) == 0x10)) {
+                    // prevent that one of the transactionID bytes is 0x10, which has to be escaped by double 0x10 and makes life a lot harder
+                    transactionId = this.transactionId.getAndIncrement();
+                }
+                logger.debug("Creating request for offset {}, with length {} and transaction id {}", address, size, transactionId);
+
+                requests.put(transactionId, msg);
+
+                switch (((Df1Field) field).getAddress_type()) {
+                    case OFFSET:
+                        out.add(new DF1UnprotectedReadRequest((short) 0x00, (short)transactionId, address, size));
+                        break;
+                    case LOGICAL:
+                        // TODO: add 'protected typed logical read' to mspec
+                        throw new NotImplementedException("not yet implemented in mspec");
+                }
+
+            }
+        } else {
+            throw new IllegalStateException("This should not happen!");
+        }
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, DF1Symbol msg, List<Object> out) throws Exception {
+        logger.debug("Received DF1 Command incoming {}", msg);
+
+        if (msg instanceof DF1SymbolMessageFrameNAK) {
+            logger.warn("Received a response NAK, notify all requests");
+            for (Map.Entry<Integer, PlcRequestContainer> entry : requests.entrySet()) {
+                entry.getValue().getResponseFuture().complete(
+                    new DefaultPlcReadResponse(
+                        ((InternalPlcReadRequest) entry.getValue().getRequest()),
+                        Collections.singletonMap("erster", Pair.of(PlcResponseCode.INTERNAL_ERROR, new DefaultIntegerFieldItem(-1)))
+                    ));
+            }
+            return;
+        } else if (msg instanceof DF1SymbolMessageFrameACK) {
+            logger.warn("Received a response ACK :D");
+            return;
+        }
+
+        assert msg instanceof DF1SymbolMessageFrame;
+
+        DF1Command command = ((DF1SymbolMessageFrame) msg).getCommand();
+        int transactionId = command.getTransactionCounter();
+        if (!requests.containsKey(transactionId)) {
+            logger.warn("Received a response to unknown transaction id {}", transactionId);
+            ctx.fireExceptionCaught(new RuntimeException("Received a response to unknown transaction id"));
+            ctx.close();
+            return;
+        }
+        // As every response has a matching request, get this request based on the tpdu.
+        PlcRequestContainer requestContainer = requests.remove(transactionId);
+        PlcRequest request = requestContainer.getRequest();
+
+        // Handle the response.
+        PlcResponse response = null;
+        if (request instanceof PlcReadRequest) {
+            /*
+            Things to do
+            - check response code (if there is something like that?
+            - cast the bytes to right datatype
+            - create Response
+             */
+            // We can do this as we have only one fieldName in DF1
+            final String fieldName = ((PlcReadRequest) request).getFieldNames().iterator().next();
+            // TODO can there be another code than ok?
+            final PlcResponseCode responseCode = PlcResponseCode.OK;
+            // TODO maybe check for different status bytes
+            final Df1Field field = (Df1Field) ((PlcReadRequest) request).getField(fieldName);
+            // Cast byte and create response item
+            BaseDefaultFieldItem responseItem = null;
+            short[] data = ((DF1UnprotectedReadResponse)command).getData();
+            switch (field.getDataType()) {
+                case BIT:
+                    break;
+                case INTEGER:
+                    // TODO: type conversion is untested
+                    responseItem = new DefaultIntegerFieldItem((int)data[0] + ((int) data[1] << 8));
+                    break;
+                case FLOAT:
+                    break;
+                case BIT_STRING:
+                    break;
+                case ARRAY:
+                    break;
+                // TODO add all other cases here...
+                default:
+                    throw new NotImplementedException("The DataType " + field.getDataType() + " is currently not implemented!");
+            }
+            response = new DefaultPlcReadResponse(((InternalPlcReadRequest) request),
+                Collections.singletonMap(fieldName,
+                    Pair.of(responseCode, responseItem)));
+        } else if (request instanceof PlcWriteRequest) {
+            logger.warn("Writing is currently not implemented but received a write response?!");
+            ctx.close();
+            throw new NotImplementedException("This is currently not implemented!");
+        }
+
+        // Confirm the response being handled.
+        if (response != null) {
+            requestContainer.getResponseFuture().complete(response);
+        }
+    }
+
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/DF1Utils.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/DF1Utils.java
new file mode 100644
index 0000000..820517e
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/DF1Utils.java
@@ -0,0 +1,158 @@
+/*
+ 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.df1.readwrite.DF1Command;
+import org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadRequest;
+import org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse;
+import org.apache.plc4x.java.utils.ParseException;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+
+public class DF1Utils {
+
+    public static short crcCheck(Object... args) {
+        short destinationAddress = (short) args[0];
+        short sourceAddress = (short) args[1];
+        DF1Command command = (DF1Command) args[2];
+        short commandDiscriminatorValues = (short) command.getDiscriminatorValues()[0];
+        short status = command.getStatus();
+        int transactionCounter = command.getTransactionCounter();
+        if(command instanceof DF1UnprotectedReadRequest) {
+            try {
+                DF1UnprotectedReadRequest unprotectedReadRequest = (DF1UnprotectedReadRequest) command;
+                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) transactionCounter);
+                writeBuffer.writeUnsignedInt(16, (short) unprotectedReadRequest.getAddress());
+                writeBuffer.writeUnsignedShort(8, (byte) unprotectedReadRequest.getSize());
+                writeBuffer.writeUnsignedShort(8, (byte) 0x03);
+
+                byte[] data = writeBuffer.getData();
+                return calculateCRC(data);
+
+            } catch (ParseException e) {
+                throw new RuntimeException("Something went wrong during the CRC check", e);
+            }
+        } else if(command instanceof DF1UnprotectedReadResponse) {
+            DF1UnprotectedReadResponse unprotectedReadResponseCommand = (DF1UnprotectedReadResponse) command;
+            try {
+                // TODO: size has to be dependent on actual size requested
+                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) transactionCounter);
+                boolean escape10 = false;
+                for (short data : unprotectedReadResponseCommand.getData()) {
+//                    if (escape10 == true){
+//                        if (data == 0x10) {
+//
+//                        }
+//                    } else{
+//
+//                    }
+                    writeBuffer.writeUnsignedShort(8,  data);
+                }
+                writeBuffer.writeUnsignedShort(8, (byte) 0x03);
+
+                byte[] data = writeBuffer.getData();
+                return calculateCRC(data);
+
+            } catch (ParseException e) {
+                throw new RuntimeException("Something went wrong during the CRC check", e);
+            }
+        }
+
+        return 0;
+    }
+
+    public static boolean dataTerminate(ReadBuffer io) {
+        try {
+            // The byte sequence 0x10 followed by 0x03 indicates the end of the message,
+            // so if we would read this, we abort the loop and stop reading data.
+            if ((io.peekByte(0) == (byte) 0x10) && (io.peekByte(1) == (byte) 0x03)) {
+                return true;
+            }
+        } catch (ParseException e) {
+            // Just ignore and return false.
+        }
+        return false;
+    }
+
+    public static short readData(ReadBuffer io) {
+        try {
+            // If we read a 0x10, this has to be followed by another 0x10, which is how
+            // this value is escaped in DF1, so if we encounter two 0x10, we simply ignore the first.
+            if ((io.peekByte(0) == (byte) 0x10) && (io.peekByte(1) == 0x10)) {
+                io.readByte(8);
+            }
+            return io.readUnsignedShort(8);
+        } catch (ParseException e) {
+            throw new RuntimeException("Error parsing data", e);
+        }
+    }
+
+    public static void writeData(WriteBuffer io, short data) {
+        try {
+            // If a value is 0x10, this has to be duplicated in order to be escaped.
+            if ((data == (short) 0x10)) {
+                io.writeUnsignedShort(8, (short) 0x10);
+            }
+            io.writeUnsignedShort(8, data);
+        } catch (ParseException e) {
+            throw new RuntimeException("Error parsing data", e);
+        }
+    }
+
+    public static int dataLength(short[] data) {
+        int i = 0;
+        for(short dataByte : data) {
+            // If a value is 0x10, this has to be duplicated which increases the message size by one.
+            if(dataByte == 0x10) {
+                i++;
+            }
+            i++;
+        }
+        return i;
+    }
+
+    private static short calculateCRC(byte[] 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 (short)tmp;
+    }
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/Df1FieldHandler.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/Df1FieldHandler.java
new file mode 100644
index 0000000..4b92194
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/util/Df1FieldHandler.java
@@ -0,0 +1,39 @@
+/*
+ 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;
+import org.apache.plc4x.java.df1.Df1Field;
+
+public class Df1FieldHandler extends DefaultPlcFieldHandler {
+
+    @Override
+    public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+        return Df1Field.of(fieldQuery);
+    }
+
+    @Override
+    public BaseDefaultFieldItem encodeByte(PlcField field, Object[] values) {
+        return super.encodeByte(field, values);
+    }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
new file mode 100644
index 0000000..f59c2cd
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.plc4x.java.amsads.AMSADSPlcDriver
diff --git a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/java/amsads/AMSADSPlcDriverTest.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/java/amsads/AMSADSPlcDriverTest.java
new file mode 100644
index 0000000..5057086
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/java/amsads/AMSADSPlcDriverTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.regex.Matcher;
+
+import static org.apache.plc4x.java.df1.DF1PlcDriver.DF1_URI_PATTERN;
+import static org.apache.plc4x.java.df1.DF1PlcDriver.SERIAL_PATTERN;
+
+public class AMSADSPlcDriverTest {
+
+    @Test
+    public void matchExpression() {
+        Matcher matcher = SERIAL_PATTERN.matcher("serial:///COM4");
+
+        Assertions.assertTrue(matcher.matches());
+    }
+
+    @Test
+    public void matchExpression2() {
+        Matcher matcher = DF1_URI_PATTERN.matcher("df1:serial:///COM4");
+
+        Assertions.assertTrue(matcher.matches());
+    }
+}
\ No newline at end of file
diff --git a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkGeneratedDf1.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkGeneratedDf1.java
new file mode 100644
index 0000000..27c9be2
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkGeneratedDf1.java
@@ -0,0 +1,81 @@
+/*
+ * 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.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-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkManualDf1.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkManualDf1.java
new file mode 100644
index 0000000..7e4141b
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/BenchmarkManualDf1.java
@@ -0,0 +1,239 @@
+/*
+ * 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;
+
+public class BenchmarkManualDf1 {
+
+    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);
+
+        byte[] msg = {0x10, 0x02,   0x09, 0x00,   0x01, 0x00,   0x01, 0x00,   0x0b, 0x00,   0x02,   0x10, 0x03};
+        comPort.writeBytes(msg, 13);
+
+
+//        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[] crcmsg = { 0x09, 0x00,   0x01, 0x00,   0x01, 0x00,   0x0b, 0x00,   0x02,   0x03};
+
+        int[] c_CRC = CalcCRC(crcmsg);
+        byte[] crc1 = {(byte)c_CRC[0]};
+        byte[] crc2 = {(byte)c_CRC[1]};
+        System.out.println("crc1: " + Integer.toHexString(crc1[0]));
+        System.out.println("crc2: " + Integer.toHexString(crc2[0]));
+        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-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/Df1Test.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/Df1Test.java
new file mode 100644
index 0000000..bcadf1a
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/Df1Test.java
@@ -0,0 +1,30 @@
+/*
+  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 org.apache.plc4x.protocol.test.ProtocolTestsuiteRunner;
+
+public class Df1Test extends ProtocolTestsuiteRunner {
+
+    public Df1Test() {
+        super("/testsuite/Df1Testsuite.xml");
+    }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/EndToEndTest.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/EndToEndTest.java
new file mode 100644
index 0000000..42e2635
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/EndToEndTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * TODO write comment
+ *
+ * @author julian
+ * Created by julian on 2019-08-07
+ */
+public class EndToEndTest {
+
+    @Test
+    public void helloDf1() {
+        try (PlcConnection plcConnection = new PlcDriverManager().getConnection("df1:serial:///COM4")) {
+            PlcReadRequest request = plcConnection.readRequestBuilder()
+                .addItem("hurz", "5:INTEGER")
+                .build();
+
+            PlcReadResponse response = request.execute().get(100, TimeUnit.SECONDS);
+
+
+            // TODO: get the actual read bytes from the response
+            System.out.println(response);
+            System.out.println("Response code was " + response.getResponseCode("erster"));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/IOTest.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/IOTest.java
new file mode 100644
index 0000000..6179b7f
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/IOTest.java
@@ -0,0 +1,99 @@
+/*
+ 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.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.plc4x.java.df1.readwrite.DF1Symbol;
+import org.apache.plc4x.java.df1.readwrite.io.DF1SymbolIO;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.junit.jupiter.api.Test;
+
+public class IOTest {
+
+    @Test
+    public void testXml() throws Exception {
+        byte[] rData = Hex.decodeHex("10020900010001001100021003546F");
+        ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+        ReadBuffer rBuf = new ReadBuffer(rData, false);
+        DF1Symbol symbol = new DF1SymbolIO().parse(rBuf);
+        String xml = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(symbol);
+        System.out.println(xml);
+        DF1Symbol symbol2 = mapper.readValue(xml, DF1Symbol.class);
+        System.out.println(symbol2);
+    }
+
+    @Test
+    public void testJson() throws Exception {
+        byte[] rData = Hex.decodeHex("10020A0941000100FFFF1003DFB9");
+        ObjectMapper mapper = new ObjectMapper().enableDefaultTyping();
+        ReadBuffer rBuf = new ReadBuffer(rData, false);
+        DF1Symbol symbol = new DF1SymbolIO().parse(rBuf);
+        String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(symbol);
+        System.out.println(json);
+        DF1Symbol symbol2 = mapper.readValue(json, DF1Symbol.class);
+        System.out.println(symbol2);
+    }
+
+    /*@Test
+    public void testParser() throws Exception {
+        byte[] rData = Hex.decodeHex("0610020500180801c0a82a46c4090801c0a82a46c40a0203");
+        long start = System.currentTimeMillis();
+        int numRunsParse = 20000;
+
+        KNXNetIPMessageIO knxNetIPMessageIO = new KNXNetIPMessageIO();
+
+        // Benchmark the parsing code
+        KNXNetIPMessage packet = null;
+        for(int i = 0; i < numRunsParse; i++) {
+            ReadBuffer rBuf = new ReadBuffer(rData);
+            packet = knxNetIPMessageIO.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 = 20000;
+        byte[] oData = null;
+        for(int i = 0; i < numRunsSerialize; i++) {
+            WriteBuffer wBuf = new WriteBuffer(packet.getLengthInBytes());
+            knxNetIPMessageIO.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");
+        }
+    }*/
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/test/resources/testsuite/Df1Testsuite.xml b/sandbox/test-java-amsads-driver/src/test/resources/testsuite/Df1Testsuite.xml
new file mode 100644
index 0000000..27dcbec
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/resources/testsuite/Df1Testsuite.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/testsuite.xsd"
+                bigEndian="true">
+
+  <name>Allen-Bradley DF1</name>
+
+  <testcase>
+    <name>Unprotected Read Address Request</name>
+    <raw>10020900010001001100021003546F</raw>
+    <root-type>DF1Symbol</root-type>
+    <xml>
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
+        <destinationAddress>9</destinationAddress>
+        <sourceAddress>0</sourceAddress>
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadRequest">
+          <status>0</status>
+          <transactionCounter>1</transactionCounter>
+          <address>17</address>
+          <size>2</size>
+        </command>
+      </DF1SymbolMessageFrame>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Unprotected Read Address Response</name>
+    <raw>10020A0941000100FFFF1003DFB9</raw>
+    <root-type>DF1Symbol</root-type>
+    <xml>
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
+        <destinationAddress>10</destinationAddress>
+        <sourceAddress>9</sourceAddress>
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse">
+          <status>0</status>
+          <transactionCounter>1</transactionCounter>
+          <data>
+            <data>255</data>
+            <data>255</data>
+          </data>
+        </command>
+      </DF1SymbolMessageFrame>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Unprotected Read Address Response (Containing 0x10 in the data)</name>
+    <raw>10020A09410001001010FF1003BAAD</raw>
+    <root-type>DF1Symbol</root-type>
+    <xml>
+      <DF1SymbolMessageFrame className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrame">
+        <destinationAddress>10</destinationAddress>
+        <sourceAddress>9</sourceAddress>
+        <command className="org.apache.plc4x.java.df1.readwrite.DF1UnprotectedReadResponse">
+          <status>0</status>
+          <transactionCounter>1</transactionCounter>
+          <data>
+            <data>16</data>
+            <data>255</data>
+          </data>
+        </command>
+      </DF1SymbolMessageFrame>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>ACK Response</name>
+    <raw>1006</raw>
+    <root-type>DF1Symbol</root-type>
+    <xml>
+      <DF1SymbolMessageFrameACK className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrameACK"/>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>NACK Response</name>
+    <raw>1015</raw>
+    <root-type>DF1Symbol</root-type>
+    <xml>
+      <DF1SymbolMessageFrameNAK className="org.apache.plc4x.java.df1.readwrite.DF1SymbolMessageFrameNAK"/>
+    </xml>
+  </testcase>
+
+</test:testsuite>
\ No newline at end of file