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 2018/02/02 08:08:42 UTC
[incubator-plc4x] branch feature/Beckhoff_ADS_protocol updated:
added simple ADSPlcConnection implementation.
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch feature/Beckhoff_ADS_protocol
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
The following commit(s) were added to refs/heads/feature/Beckhoff_ADS_protocol by this push:
new bba1470 added simple ADSPlcConnection implementation.
bba1470 is described below
commit bba1470b70012e7194aaef59c2585247d97b1878
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Feb 2 09:08:37 2018 +0100
added simple ADSPlcConnection implementation.
---
.../org/apache/plc4x/java/ads/ADSPlcDriver.java | 4 +-
.../plc4x/java/ads/api/generic/types/AMSNetId.java | 16 +++
.../plc4x/java/ads/api/generic/types/AMSPort.java | 12 +-
.../types/AMSPort.java => package-info.java} | 28 +---
.../java/ads/connection/ADSPlcConnection.java | 154 +++++++++++++++++++++
.../types/AMSPort.java => model/ADSAddress.java} | 28 ++--
.../types/AMSPort.java => model/package-info.java} | 27 +---
7 files changed, 202 insertions(+), 67 deletions(-)
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
index 0b2ea3c..d1bcd0d 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
@@ -37,9 +37,9 @@ import java.util.regex.Pattern;
public class ADSPlcDriver implements PlcDriver {
private static final Pattern ADS_ADDRESS_PATTERN =
- Pattern.compile("^(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_REGEX + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_REGEX + ")"
+ Pattern.compile("^(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")"
+ "/"
- + "(?<sourceAmsNetId>" + AMSNetId.AMS_NET_ID_REGEX + "):(?<sourceAmsPort>" + AMSPort.AMS_PORT_REGEX + ")");
+ + "(?<sourceAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<sourceAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")");
private static final Pattern ADS_URI_PATTERN = Pattern.compile("^ads://(?<host>\\w+)/" + ADS_ADDRESS_PATTERN);
@Override
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
index c69299e..73fc07d 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSNetId.java
@@ -18,8 +18,12 @@
*/
package org.apache.plc4x.java.ads.api.generic.types;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.plc4x.java.ads.api.util.ByteValue;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
/**
* The AMSNetId consists of 6 bytes and addresses the transmitter or receiver. One possible AMSNetId would be e.g.. 172.16.17.10.1.1. The storage arrangement in this example is as follows:
* <p>
@@ -33,6 +37,9 @@ import org.apache.plc4x.java.ads.api.util.ByteValue;
*/
public class AMSNetId extends ByteValue {
+ public static final Pattern AMS_NET_ID_PATTERN =
+ Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
+
public static final int NUM_BYTES = 6;
AMSNetId(byte... values) {
@@ -47,4 +54,13 @@ public class AMSNetId extends ByteValue {
public static AMSNetId of(int octed1, int octed2, int octed3, int octed4, int octed5, int octed6) {
return new AMSNetId((byte) octed1, (byte) octed2, (byte) octed3, (byte) octed4, (byte) octed5, (byte) octed6);
}
+
+ public static AMSNetId of(String address) {
+ if (!AMS_NET_ID_PATTERN.matcher(address).matches()) {
+ throw new IllegalArgumentException(address + " must match " + AMS_NET_ID_PATTERN);
+ }
+ String[] split = address.split("\\.");
+ byte[] bytes = ArrayUtils.toPrimitive(Stream.of(split).map(Integer::parseInt).map(Integer::byteValue).toArray(Byte[]::new));
+ return new AMSNetId(bytes);
+ }
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
index d030a3a..e5e9c28 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
@@ -21,10 +21,13 @@ package org.apache.plc4x.java.ads.api.generic.types;
import org.apache.plc4x.java.ads.api.util.ByteValue;
import java.nio.ByteBuffer;
+import java.util.regex.Pattern;
public class AMSPort extends ByteValue {
- private static final int NUM_BYTES = 2;
+ public static final Pattern AMS_PORT_PATTERN = Pattern.compile("\\d+");
+
+ public static final int NUM_BYTES = 2;
AMSPort(byte... value) {
super(value);
@@ -38,4 +41,11 @@ public class AMSPort extends ByteValue {
public static AMSPort of(int port) {
return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array());
}
+
+ public static AMSPort of(String port) {
+ if (!AMS_PORT_PATTERN.matcher(port).matches()) {
+ throw new IllegalArgumentException(port + " must match " + AMS_PORT_PATTERN);
+ }
+ return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(Integer.parseInt(port)).array());
+ }
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/package-info.java
similarity index 59%
copy from plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
copy to plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/package-info.java
index d030a3a..6bca8c9 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/package-info.java
@@ -16,26 +16,8 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.ads.api.generic.types;
-
-import org.apache.plc4x.java.ads.api.util.ByteValue;
-
-import java.nio.ByteBuffer;
-
-public class AMSPort extends ByteValue {
-
- private static final int NUM_BYTES = 2;
-
- AMSPort(byte... value) {
- super(value);
- assertLength(NUM_BYTES);
- }
-
- public static AMSPort of(byte... values) {
- return new AMSPort(values);
- }
-
- public static AMSPort of(int port) {
- return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array());
- }
-}
+/**
+ * This package contains a replication of the specification found online.
+ * @see <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tcadsamsspec/html/tcadsamsspec_intro.htm">ADS SPEC</a>
+ */
+package org.apache.plc4x.java.ads.api;
\ No newline at end of file
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java
new file mode 100644
index 0000000..a6b7ba6
--- /dev/null
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/ADSPlcConnection.java
@@ -0,0 +1,154 @@
+/*
+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.ads.connection;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import org.apache.plc4x.java.ads.api.generic.types.AMSNetId;
+import org.apache.plc4x.java.ads.api.generic.types.AMSPort;
+import org.apache.plc4x.java.ads.model.ADSAddress;
+import org.apache.plc4x.java.ads.netty.Plc4XADSProtocol;
+import org.apache.plc4x.java.api.connection.AbstractPlcConnection;
+import org.apache.plc4x.java.api.connection.PlcReader;
+import org.apache.plc4x.java.api.connection.PlcWriter;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.exceptions.PlcException;
+import org.apache.plc4x.java.api.messages.*;
+import org.apache.plc4x.java.api.model.Address;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ADSPlcConnection extends AbstractPlcConnection implements PlcReader, PlcWriter {
+
+ private static final int TCP_PORT = 48898;
+
+ private final String hostName;
+
+ private final int pduSize;
+
+ private final AMSNetId targetAmsNetId;
+ private final AMSPort targetAmsPort;
+ private final AMSNetId sourceAmsNetId;
+ private final AMSPort sourceAmsPort;
+
+ private EventLoopGroup workerGroup;
+ private Channel channel;
+
+ public ADSPlcConnection(String hostName, AMSNetId targetAmsNetId, AMSPort targetAmsPort, AMSNetId sourceAmsNetId, AMSPort sourceAmsPort) {
+ this.hostName = hostName;
+ this.pduSize = 1024;
+ this.targetAmsNetId = targetAmsNetId;
+ this.targetAmsPort = targetAmsPort;
+ this.sourceAmsNetId = sourceAmsNetId;
+ this.sourceAmsPort = sourceAmsPort;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ public int getPduSize() {
+ return pduSize;
+ }
+
+ @Override
+ public void connect() throws PlcConnectionException {
+ workerGroup = new NioEventLoopGroup();
+
+ try {
+ // As we don't just want to wait till the connection is established,
+ // define a future we can use to signal back that the ads session is
+ // finished initializing.
+ CompletableFuture<Void> sessionSetupCompleteFuture = new CompletableFuture<>();
+
+ InetAddress serverInetAddress = InetAddress.getByName(hostName);
+
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.group(workerGroup);
+ bootstrap.channel(NioSocketChannel.class);
+ bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
+ bootstrap.option(ChannelOption.TCP_NODELAY, true);
+ bootstrap.handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(Channel channel) throws Exception {
+ // Build the protocol stack for communicating with the ads protocol.
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(new Plc4XADSProtocol());
+ }
+ });
+ // Start the client.
+ ChannelFuture f = bootstrap.connect(serverInetAddress, TCP_PORT).sync();
+ f.awaitUninterruptibly();
+ // Wait till the session is finished initializing.
+ channel = f.channel();
+
+ sessionSetupCompleteFuture.get();
+ } catch (UnknownHostException e) {
+ throw new PlcConnectionException("Unknown Host " + hostName, e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new PlcConnectionException(e);
+ } catch (ExecutionException e) {
+ throw new PlcConnectionException(e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ workerGroup.shutdownGracefully();
+ }
+
+ @Override
+ public Address parseAddress(String addressString) throws PlcException {
+ Matcher matcher = Pattern.compile("(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")").matcher(addressString);
+ if (!matcher.matches()) {
+ throw new PlcConnectionException(
+ "Address string doesn't match the format '{targetAmsNetId}:{targetAmsPort}'");
+ }
+ AMSNetId targetAmsNetId = AMSNetId.of(matcher.group("targetAmsNetId"));
+ AMSPort targetAmsPort = AMSPort.of(matcher.group("targetAmsPort"));
+ return new ADSAddress(targetAmsNetId, targetAmsPort);
+ }
+
+ @Override
+ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+ CompletableFuture<PlcReadResponse> readFuture = new CompletableFuture<>();
+ PlcRequestContainer<PlcReadRequest, PlcReadResponse> container =
+ new PlcRequestContainer<>(readRequest, readFuture);
+ channel.writeAndFlush(container);
+ return readFuture;
+ }
+
+ @Override
+ public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
+ CompletableFuture<PlcWriteResponse> writeFuture = new CompletableFuture<>();
+ PlcRequestContainer<PlcWriteRequest, PlcWriteResponse> container =
+ new PlcRequestContainer<>(writeRequest, writeFuture);
+ channel.writeAndFlush(container);
+ return writeFuture;
+ }
+
+}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/ADSAddress.java
similarity index 60%
copy from plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
copy to plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/ADSAddress.java
index d030a3a..66bb617 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/ADSAddress.java
@@ -16,26 +16,18 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.ads.api.generic.types;
+package org.apache.plc4x.java.ads.model;
-import org.apache.plc4x.java.ads.api.util.ByteValue;
+import org.apache.plc4x.java.ads.api.generic.types.AMSNetId;
+import org.apache.plc4x.java.ads.api.generic.types.AMSPort;
+import org.apache.plc4x.java.api.model.Address;
-import java.nio.ByteBuffer;
+public class ADSAddress implements Address {
+ public final AMSNetId targetAmsNetId;
+ public final AMSPort targetAmsPort;
-public class AMSPort extends ByteValue {
-
- private static final int NUM_BYTES = 2;
-
- AMSPort(byte... value) {
- super(value);
- assertLength(NUM_BYTES);
- }
-
- public static AMSPort of(byte... values) {
- return new AMSPort(values);
- }
-
- public static AMSPort of(int port) {
- return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array());
+ public ADSAddress(AMSNetId targetAmsNetId, AMSPort targetAmsPort) {
+ this.targetAmsNetId = targetAmsNetId;
+ this.targetAmsPort = targetAmsPort;
}
}
diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/package-info.java
similarity index 59%
copy from plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
copy to plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/package-info.java
index d030a3a..a99929a 100644
--- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AMSPort.java
+++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/package-info.java
@@ -16,26 +16,7 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.ads.api.generic.types;
-
-import org.apache.plc4x.java.ads.api.util.ByteValue;
-
-import java.nio.ByteBuffer;
-
-public class AMSPort extends ByteValue {
-
- private static final int NUM_BYTES = 2;
-
- AMSPort(byte... value) {
- super(value);
- assertLength(NUM_BYTES);
- }
-
- public static AMSPort of(byte... values) {
- return new AMSPort(values);
- }
-
- public static AMSPort of(int port) {
- return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array());
- }
-}
+/**
+ * This package contains plc4x specific modeling.
+ */
+package org.apache.plc4x.java.ads.model;
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
sruehl@apache.org.