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 813415f added some basic tests and commited the missing parts 813415f is described below commit 813415f32f73124b7b54fc2f7a87e7bf92e3acc6 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Fri Feb 2 10:07:11 2018 +0100 added some basic tests and commited the missing parts --- plc4j/protocols/ads/pom.xml | 6 ++ .../org/apache/plc4x/java/ads/ADSPlcDriver.java | 15 +-- .../plc4x/java/ads/api/generic/types/AMSNetId.java | 6 ++ .../plc4x/java/ads/api/generic/types/AMSPort.java | 9 +- .../java/ads/connection/ADSPlcConnection.java | 26 +++++- .../plc4x/java/ads/netty/Plc4XADSProtocol.java | 85 +++++++++++++++++ .../services/org.apache.plc4x.java.api.PlcDriver | 19 ++++ plc4j/protocols/ads/src/site/asciidoc/index.adoc | 101 +++++++++++++++++++++ .../apache/plc4x/java/ads/ADSPlcDriverTest.java | 56 ++++++++++++ .../java/ads/connection/ADSPlcConnectionTests.java | 72 +++++++++++++++ plc4j/protocols/ads/src/test/resources/logback.xml | 36 ++++++++ 11 files changed, 418 insertions(+), 13 deletions(-) diff --git a/plc4j/protocols/ads/pom.xml b/plc4j/protocols/ads/pom.xml index 273084c..2eb013e 100644 --- a/plc4j/protocols/ads/pom.xml +++ b/plc4j/protocols/ads/pom.xml @@ -68,6 +68,12 @@ </dependency> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.7</version> + </dependency> + + <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <scope>test</scope> 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 d1bcd0d..2b9b3b6 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,10 @@ import java.util.regex.Pattern; public class ADSPlcDriver implements PlcDriver { private static final Pattern ADS_ADDRESS_PATTERN = - Pattern.compile("^(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")" - + "/" - + "(?<sourceAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<sourceAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")"); + Pattern.compile("(?<targetAmsNetId>" + AMSNetId.AMS_NET_ID_PATTERN + "):(?<targetAmsPort>" + AMSPort.AMS_PORT_PATTERN + ")" + + "(/" + + "(?<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 @@ -57,13 +58,15 @@ public class ADSPlcDriver implements PlcDriver { Matcher matcher = ADS_URI_PATTERN.matcher(url); if (!matcher.matches()) { throw new PlcConnectionException( - "Connection url doesn't match the format 'ads://{host|ip}/{targetAmsNetId}:{targetAmsPort}/{sourceAmsNetId}:{sourceAmsPort}'"); + "Connection url " + url + " doesn't match 'ads://{host|ip}/{targetAmsNetId}:{targetAmsPort}/{sourceAmsNetId}:{sourceAmsPort}' RAW:" + ADS_URI_PATTERN); } String host = matcher.group("host"); AMSNetId targetAmsNetId = AMSNetId.of(matcher.group("targetAmsNetId")); AMSPort targetAmsPort = AMSPort.of(matcher.group("targetAmsPort")); - AMSNetId sourceAmsNetId = AMSNetId.of(matcher.group("sourceAmsNetId")); - AMSPort sourceAmsPort = AMSPort.of(matcher.group("sourceAmsPort")); + String sourceAmsNetIdString = matcher.group("sourceAmsNetId"); + AMSNetId sourceAmsNetId = sourceAmsNetIdString != null ? AMSNetId.of(sourceAmsNetIdString) : null; + String sourceAmsPortString = matcher.group("sourceAmsPort"); + AMSPort sourceAmsPort = sourceAmsPortString != null ? AMSPort.of(sourceAmsPortString) : null; return new ADSPlcConnection(host, targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort); } 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 73fc07d..0c5917f 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 @@ -63,4 +63,10 @@ public class AMSNetId extends ByteValue { byte[] bytes = ArrayUtils.toPrimitive(Stream.of(split).map(Integer::parseInt).map(Integer::byteValue).toArray(Byte[]::new)); return new AMSNetId(bytes); } + + @Override + public String toString() { + byte[] bytes = getBytes(); + return bytes[0] + "." + bytes[1] + "." + bytes[2] + "." + bytes[3] + "." + bytes[4] + "." + bytes[5]; + } } 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 e5e9c28..ab8a1c1 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 @@ -39,13 +39,18 @@ public class AMSPort extends ByteValue { } public static AMSPort of(int port) { - return new AMSPort(ByteBuffer.allocate(NUM_BYTES).putInt(port).array()); + return new AMSPort(ByteBuffer.allocate(NUM_BYTES).put((byte) (port & 0xff)).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()); + return of(Integer.parseInt(port)); + } + + @Override + public String toString() { + return "" + getBytes()[0]; } } 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 index a6b7ba6..92ae31f 100644 --- 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 @@ -47,19 +47,23 @@ public class ADSPlcConnection extends AbstractPlcConnection implements PlcReader 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) { + this(hostName, targetAmsNetId, targetAmsPort, null, null); + } + 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; @@ -70,8 +74,20 @@ public class ADSPlcConnection extends AbstractPlcConnection implements PlcReader return hostName; } - public int getPduSize() { - return pduSize; + public AMSNetId getTargetAmsNetId() { + return targetAmsNetId; + } + + public AMSPort getTargetAmsPort() { + return targetAmsPort; + } + + public AMSNetId getSourceAmsNetId() { + return sourceAmsNetId; + } + + public AMSPort getSourceAmsPort() { + return sourceAmsPort; } @Override diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java new file mode 100644 index 0000000..358e33b --- /dev/null +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/netty/Plc4XADSProtocol.java @@ -0,0 +1,85 @@ +/* +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.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import org.apache.plc4x.java.api.exceptions.PlcException; +import org.apache.plc4x.java.api.exceptions.PlcProtocolException; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcRequest; +import org.apache.plc4x.java.api.messages.PlcRequestContainer; +import org.apache.plc4x.java.api.messages.PlcWriteRequest; +import org.apache.plc4x.java.api.messages.items.ReadRequestItem; +import org.apache.plc4x.java.api.messages.items.WriteRequestItem; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class Plc4XADSProtocol extends MessageToMessageCodec<ByteBuf, PlcRequestContainer> { + + private static final AtomicInteger tpduGenerator = new AtomicInteger(1); + + private Map<Short, PlcRequestContainer> requests; + + public Plc4XADSProtocol() { + this.requests = new HashMap<>(); + } + + @Override + protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception { + PlcRequest request = msg.getRequest(); + if (request instanceof PlcReadRequest) { + encodeReadRequest(msg, out); + } else if (request instanceof PlcWriteRequest) { + encodeWriteRequest(msg, out); + } + } + + private void encodeWriteRequest(PlcRequestContainer msg, List<Object> out) throws PlcException { + PlcWriteRequest writeRequest = (PlcWriteRequest) msg.getRequest(); + if (writeRequest.getRequestItems().size() != 1) { + throw new PlcProtocolException("Only one item supported"); + } + WriteRequestItem<?> writeRequestItem = writeRequest.getRequestItems().get(0); + + out.add(Unpooled.buffer()); + } + + private void encodeReadRequest(PlcRequestContainer msg, List<Object> out) throws PlcException { + PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest(); + + if (readRequest.getRequestItems().size() != 1) { + throw new PlcProtocolException("Only one item supported"); + } + ReadRequestItem<?> readRequestItem = readRequest.getRequestItems().get(0); + out.add(Unpooled.buffer()); + } + + @SuppressWarnings("unchecked") + @Override + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception { + + } + +} diff --git a/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver b/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver new file mode 100644 index 0000000..0cdd1b3 --- /dev/null +++ b/plc4j/protocols/ads/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.plc4x.java.ads.ADSPlcDriver diff --git a/plc4j/protocols/ads/src/site/asciidoc/index.adoc b/plc4j/protocols/ads/src/site/asciidoc/index.adoc new file mode 100644 index 0000000..1f37781 --- /dev/null +++ b/plc4j/protocols/ads/src/site/asciidoc/index.adoc @@ -0,0 +1,101 @@ +// +// 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. +// +:imagesdir: ./img/ + +== ADS Protocol Java Implementation + +The current version of the ADS protocol java driver is based upon Netty 4 (http://netty.io/). + +As the ADS protocol running on TCP is a hierarchy of protocols, the ADS driver is implemented by providing several Protocol implementations, each encoding one layer of the protocol stack. + +The complete pipeline for the ADS protocol looks like this: + +[blockdiag,ads-netty-pipeline] +.... +{ + Application -> ADSPlcConnection; + Socket -> PLC; + + group { + label = "PLC4X ADS Driver" + color = "#77FF77"; + + ADSPlcConnection -> Plc4XADSProtocol -> ADSProtocol -> IsoTPProtocol -> IsoOnTcpProtocol -> Socket + + group { + Plc4XADSProtocol; ADSProtocol; IsoTPProtocol; IsoOnTcpProtocol; + } + } +} +.... + +Each protocol layer implementation extends the class `MessageToMessageCodec` and is configured to consume/encode messages in the current format into messages of the next lower layer. + +The highest layer hereby consumes PLC4X messages, which are defined in the `plc4j-api` module, and the lowest layer produces a simple byte output. + +In order to implement the ADS Protocol as described in link:../../../protocols/ads/index.html[ADS Protocol] internally this is what happens inside the driver as soon as a connection is requested: + +[seqdiag,ads-netty-setup-communication] +.... +{ + Application; ADSPlcConnection; Plc4XADSProtocol; ADSProtocol; IsoTPProtocol; IsoOnTcpProtocol; Socket; PLC; + + group Pipeline { + "Plc4XADSProtocol"; + "ADSProtocol"; + "IsoTPProtocol"; + "IsoOnTcpProtocol"; + } + + Application -> ADSPlcConnection [label = "Calls 'connect'"] + ADSPlcConnection --> IsoTPProtocol [label = "Fires ADSConnectionEvent(INITIAL) event to the pipeline", note = "IsoTPProtocol listens for ADSConnectionEvent(INITIAL) events"] + IsoTPProtocol -> IsoOnTcpProtocol [label = "Creates new IsoOnTcp\nconnection request message"] + IsoOnTcpProtocol -> Socket [label = "Creates the byte array\ncontaining the TCP on ISO\nmessage"] + Socket -> PLC [label = "Sends the raw byte data to\nthe PLC"] + + Socket <- PLC [label = "Sends the response to the\nSocket"] + IsoOnTcpProtocol <- Socket [label = "Passes the binary data to\nthe pipeline"] + IsoTPProtocol <- IsoOnTcpProtocol [label = "Creates new IsoOnTcp message containing binary user data"] + + IsoTPProtocol --> ADSProtocol [label = "Sends ADSConnectionEvent(\nISO_TP_CONNECTION_RESPONSE_\nRECEIVED) event to the\npipeline", note = "ADSProtocol listens for ADSConnectionEvent(ISO_TP_CONNECTION_RESPONSE_RECEIVED) events"] + + IsoTPProtocol <- ADSProtocol [label = "Creates new ISO TP Data\nmessage containing an\n ADS SetupCommunictaion\nmessage"] + IsoTPProtocol -> IsoOnTcpProtocol [label = "Creates new IsoOnTcp message"] + IsoOnTcpProtocol -> Socket [label = "Creates the byte array\ncontaining the TCP on ISO\nmessage"] + Socket -> PLC [label = "Sends the raw byte data to\nthe PLC"] + + Socket <-- PLC [label = "Sends the response to the\nSocket"] + IsoOnTcpProtocol <- Socket [label = "Passes the binary data to\nthe pipeline"] + IsoTPProtocol <- IsoOnTcpProtocol [label = "Creates new IsoOnTcp message containing binary user data"] + IsoTPProtocol -> ADSProtocol + ADSPlcConnection <- ADSProtocol [label = "Sends ADSConnectionEvent(SETUP_COMPLETE) event to the\npipeline", note = "ADSPlcConnection listens for ADSConnectionEvent(SETUP_COMPLETE) events"] + +} +.... + +Above picture is a simplification. The communication of the outside with the pipeline is not implemented in a way that one component directly addresses the other. +It is more that all communication is done with the `pipeline` and Netty then takes care of calling the right component at the right time. + +When writing to the pipeline from an application Netty starts at the `top` of the pipeline and asks each pipeline level if it is able and willing to handle the current message. +If it does, the message is passed in to the `encode` method and the next component is supplied with the output of this. +If the component can't process the message the next level is checked with the unmodified message. + +When reading from the Socket the Netty processes the pipeline elements the same way, but in the opposite direction and a pipeline elements `decode` method is called instead of `encode`. + +In addition to the normal flow of messages, a Netty pipeline also provides a messaging system. Every component can fire so-called `user events` and every component can react on them by implementing a `userEventTriggered` method. + +This functionality is mainly used during connection setup to synchronize the sending of messages on the different layers of the protocol stack. \ No newline at end of file diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.java new file mode 100644 index 0000000..49585d4 --- /dev/null +++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/ADSPlcDriverTest.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.java.ads; + + +import org.apache.plc4x.java.PlcDriverManager; +import org.apache.plc4x.java.ads.connection.ADSPlcConnection; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.exceptions.PlcException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +public class ADSPlcDriverTest { + + @Disabled("We first have to find/build some tool to help test these connections.") + @Test + @Tag("fast") + void getConnection() throws PlcException { + ADSPlcConnection adsConnection = (ADSPlcConnection) + new PlcDriverManager().getConnection("ads://localhost/0.0.0.0.0.0:13"); + Assertions.assertEquals(adsConnection.getHostName(), "localhost"); + Assertions.assertEquals(adsConnection.getTargetAmsNetId().toString(), "0.0.0.0.0.0"); + Assertions.assertEquals(adsConnection.getTargetAmsPort().toString(), "13"); + } + + /** + * In this test case the 'ads' driver should report an invalid url format. + * + * @throws PlcException something went wrong + */ + @Test + @Tag("fast") + void getConnectionInvalidUrl() throws PlcException { + Assertions.assertThrows(PlcConnectionException.class, + () -> new PlcDriverManager().getConnection("ads://localhost/hurz/2")); + } + +} diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java new file mode 100644 index 0000000..8bb0d73 --- /dev/null +++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/connection/ADSPlcConnectionTests.java @@ -0,0 +1,72 @@ +/* +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 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.api.exceptions.PlcException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ADSPlcConnectionTests { + + private ADSPlcConnection adsPlcConnection; + + @BeforeEach + void setUp() { + adsPlcConnection = new ADSPlcConnection("localhost", AMSNetId.of("0.0.0.0.0.0"), AMSPort.of(13)); + } + + @AfterEach + void tearDown() { + adsPlcConnection = null; + } + + @Test + void initialState() { + assertTrue(adsPlcConnection.getHostName().equalsIgnoreCase("localhost"), "Hostname is incorrect"); + assertEquals(adsPlcConnection.getTargetAmsNetId().toString(), "0.0.0.0.0.0"); + assertEquals(adsPlcConnection.getTargetAmsPort().toString(), "13"); + } + + @Test + void emptyParseAddress() { + try { + adsPlcConnection.parseAddress(""); + } catch (PlcException exception) { + assertTrue(exception.getMessage().startsWith("Address string doesn't match"), "Unexpected exception"); + } + } + + @Test + void parseAddress() { + try { + ADSAddress address = (ADSAddress) adsPlcConnection.parseAddress("0.0.0.0.0.0:13"); + assertEquals(address.targetAmsNetId.toString(), "0.0.0.0.0.0"); + assertEquals(address.targetAmsPort.toString(), "13"); + } catch (PlcException exception) { + fail("valid data block address"); + } + } +} \ No newline at end of file diff --git a/plc4j/protocols/ads/src/test/resources/logback.xml b/plc4j/protocols/ads/src/test/resources/logback.xml new file mode 100644 index 0000000..bba8e02 --- /dev/null +++ b/plc4j/protocols/ads/src/test/resources/logback.xml @@ -0,0 +1,36 @@ +<?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. + +--> +<configuration xmlns="http://ch.qos.logback/xml/ns/logback" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd"> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- encoders are assigned the type + ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <root level="warn"> + <appender-ref ref="STDOUT" /> + </root> + +</configuration> \ No newline at end of file -- To stop receiving notification emails like this one, please contact sru...@apache.org.