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>
+
+ <!-- <!– https://mvnrepository.com/artifact/org.rxtx/rxtx –>
+ <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