You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/11/18 10:14:43 UTC
[plc4x] branch feature/plc4go updated: - Implemented a general
purpose manual testsuite class for testing all of the different datatypes.
- Fixed multiple issues in the ADS driver -- The driver was missing a
ByteLengthEstimator -- The parse methods for parsing of strings were not
implemented -- Made the ADS spec ignore the 4 trailing bytes in case of a
STRING and the 8 in case of a WSTRING - The ReadBuffer was shifting bytes
in case of little-endianness,
but was filling up in 2s complement changed that to fill with 0s - The Rea
[...]
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/plc4go by this push:
new ce53c89 - Implemented a general purpose manual testsuite class for testing all of the different datatypes. - Fixed multiple issues in the ADS driver -- The driver was missing a ByteLengthEstimator -- The parse methods for parsing of strings were not implemented -- Made the ADS spec ignore the 4 trailing bytes in case of a STRING and the 8 in case of a WSTRING - The ReadBuffer was shifting bytes in case of little-endianness, but was filling up in 2s complement changed that to fil [...]
ce53c89 is described below
commit ce53c8984bfa40fe7873a942d5dc81f60fbec41b
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Nov 18 11:14:35 2020 +0100
- Implemented a general purpose manual testsuite class for testing all of the different datatypes.
- Fixed multiple issues in the ADS driver
-- The driver was missing a ByteLengthEstimator
-- The parse methods for parsing of strings were not implemented
-- Made the ADS spec ignore the 4 trailing bytes in case of a STRING and the 8 in case of a WSTRING
- The ReadBuffer was shifting bytes in case of little-endianness, but was filling up in 2s complement changed that to fill with 0s
- The ReadRequestBuilder was sorting the fields
- Introduced a new PlcBitString PlcValue type simplifying converting byte, short, word and dword to lists of boolean values
- Added numeric constructors for the Date&Time PlcValues
-
---
plc4j/drivers/ads/pom.xml | 4 +
.../org/apache/plc4x/java/ads/ADSPlcDriver.java | 15 +++
.../apache/plc4x/java/ads/utils/StaticHelper.java | 46 ++++++-
.../plc4x/protocol/ads/ManualAdsDriverTest.java | 53 +++++---
...erTest.java => ManualParserSerializerTest.java} | 18 +--
.../plc4x/java/spi/generation/ReadBuffer.java | 6 +-
.../java/spi/messages/DefaultPlcReadRequest.java | 3 +-
.../apache/plc4x/java/spi/values/PlcBitString.java | 61 +++++++++
.../plc4x/java/spi/values/PlcTIME_OF_DAY.java | 3 +-
.../org/apache/plc4x/test/manual/ManualTest.java | 144 +++++++++++++++++++++
.../ads/src/main/resources/protocols/ads/ads.mspec | 18 +--
11 files changed, 320 insertions(+), 51 deletions(-)
diff --git a/plc4j/drivers/ads/pom.xml b/plc4j/drivers/ads/pom.xml
index d37eed2..800d57a 100644
--- a/plc4j/drivers/ads/pom.xml
+++ b/plc4j/drivers/ads/pom.xml
@@ -143,6 +143,10 @@
</dependency>
<dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-buffer</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
index d4553f2..fd5f25c 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/ADSPlcDriver.java
@@ -18,6 +18,7 @@
*/
package org.apache.plc4x.java.ads;
+import io.netty.buffer.ByteBuf;
import org.apache.plc4x.java.ads.configuration.AdsConfiguration;
import org.apache.plc4x.java.ads.field.AdsFieldHandler;
import org.apache.plc4x.java.ads.protocol.AdsProtocolLogic;
@@ -30,6 +31,8 @@ import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
+import java.util.function.ToIntFunction;
+
/**
* Implementation of the ADS protocol, based on:
* - ADS Protocol
@@ -83,9 +86,21 @@ public class ADSPlcDriver extends GeneratedDriverBase<AmsTCPPacket> {
@Override
protected ProtocolStackConfigurer<AmsTCPPacket> getStackConfigurer() {
return SingleProtocolStackConfigurer.builder(AmsTCPPacket.class, AmsTCPPacketIO.class)
+ .withPacketSizeEstimator(ByteLengthEstimator.class)
.withProtocol(AdsProtocolLogic.class)
.littleEndian()
.build();
}
+ /** Estimate the Length of a Packet */
+ public static class ByteLengthEstimator implements ToIntFunction<ByteBuf> {
+ @Override
+ public int applyAsInt(ByteBuf byteBuf) {
+ if (byteBuf.readableBytes() >= 6) {
+ return (int) byteBuf.getUnsignedIntLE(byteBuf.readerIndex() + 2) + 6;
+ }
+ return -1;
+ }
+ }
+
}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
index c374334..1ae2ca0 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
@@ -20,13 +20,55 @@ package org.apache.plc4x.java.ads.utils;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.generation.ParseException;
import org.apache.plc4x.java.spi.generation.ReadBuffer;
import org.apache.plc4x.java.spi.generation.WriteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
public class StaticHelper {
- public static String parseAmsString(ReadBuffer io, Object encoding) {
- return "";
+ public static String parseAmsString(ReadBuffer io, String encoding) {
+ try {
+ if ("UTF-8".equalsIgnoreCase(encoding)) {
+ List<Byte> bytes = new ArrayList<>();
+ while (io.hasMore(8)) {
+ final byte curByte = io.readByte(8);
+ if (curByte != 0) {
+ bytes.add(curByte);
+ } else {
+ final byte[] byteArray = new byte[bytes.size()];
+ for (int i = 0; i < bytes.size(); i++) {
+ byteArray[i] = bytes.get(i);
+ }
+ return new String(byteArray, StandardCharsets.UTF_8);
+ }
+ }
+ throw new PlcRuntimeException("Reached the end of the input without finishing the string");
+ } else if ("UTF-16".equalsIgnoreCase(encoding)) {
+ List<Byte> bytes = new ArrayList<>();
+ while (io.hasMore(16)) {
+ final short curShort = io.readShort(16);
+ if (curShort != 0) {
+ bytes.add((byte) (curShort >>> 8));
+ bytes.add((byte) (curShort & 0xFF));
+ } else {
+ final byte[] byteArray = new byte[bytes.size()];
+ for (int i = 0; i < bytes.size(); i++) {
+ byteArray[i] = bytes.get(i);
+ }
+ return new String(byteArray, StandardCharsets.UTF_16);
+ }
+ }
+ throw new PlcRuntimeException("Reached the end of the input without finishing the string");
+ } else {
+ throw new PlcRuntimeException("Unsupported string encoding " + encoding);
+ }
+ } catch (ParseException e) {
+ throw new PlcRuntimeException("Error parsing string", e);
+ }
}
public static void serializeAmsString(WriteBuffer io, PlcValue value, Object encoding) {
diff --git a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
index 4685b74..ca2b17b 100644
--- a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
+++ b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
@@ -18,31 +18,42 @@ under the License.
*/
package org.apache.plc4x.protocol.ads;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.plc4x.java.ads.readwrite.AmsTCPPacket;
-import org.apache.plc4x.java.ads.readwrite.io.AmsTCPPacketIO;
-import org.apache.plc4x.java.api.PlcConnection;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.test.manual.ManualTest;
-public class ManualAdsDriverTest {
-
- public static void main(String[] args) throws Exception {
- // Working request:
- // 000050000000c0a8171401015303c0a817c80101feff09000400300000000000000002000000 81f0000002000000080000002000000006f00000000000000400000006f0000000000000040000000300801b3702001b
- // Working response:
- // 000030000000c0a817cd0101feffc0a81714010153030900050010000000000000000100000000000000080000000000000000000000
-
- // PLC4X request:
- // 000050000000c0a8171401015303c0a817c80101feff09000400300000000000000002000000 80f0000002000000020000002000000005f000000000801d010000000000000005f000003702001d0100000000000000
- // PLC4X response:
- // 000028000000c0a817c80101feffc0a8171401015303090005000800000000000000020000000507000000000000
+import java.util.Arrays;
+public class ManualAdsDriverTest extends ManualTest {
+ public ManualAdsDriverTest(String connectionString) {
+ super(connectionString);
+ }
- byte[] data = Hex.decodeHex("000028000000c0a817c80101feffc0a8171401015303090005000800000000000000010000000507000000000000");
- ReadBuffer readBuffer = new ReadBuffer(data, true);
- final AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
- System.out.println(amsTCPPacket);
+ public static void main(String[] args) throws Exception {
+ ManualAdsDriverTest test = new ManualAdsDriverTest("ads:tcp://192.168.23.20?sourceAmsNetId=192.168.23.200.1.1&sourceAmsPort=65534&targetAmsNetId=192.168.23.20.1.1&targetAmsPort=851");
+ test.addTestCase("main.hurz_BOOL:BOOL", true);
+ test.addTestCase("main.hurz_BYTE:BYTE", Arrays.asList(false, false, true, false, true, false, true, false));
+ test.addTestCase("main.hurz_WORD:WORD", Arrays.asList(true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false));
+ test.addTestCase("main.hurz_DWORD:DWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false));
+ test.addTestCase("main.hurz_SINT:SINT", -42);
+ test.addTestCase("main.hurz_USINT:USINT", 42);
+ test.addTestCase("main.hurz_INT:INT", -2424);
+ test.addTestCase("main.hurz_UINT:UINT", 42424);
+ test.addTestCase("main.hurz_DINT:DINT", -242442424);
+ test.addTestCase("main.hurz_UDINT:UDINT", 4242442424L);
+ test.addTestCase("main.hurz_LINT:LINT", -4242442424242424242L);
+ test.addTestCase("main.hurz_ULINT:ULINT", 4242442424242424242L);
+ test.addTestCase("main.hurz_REAL:REAL", 3.14159265359F);
+ test.addTestCase("main.hurz_LREAL:LREAL", 2.71828182846D);
+ test.addTestCase("main.hurz_STRING:STRING", "hurz");
+ test.addTestCase("main.hurz_WSTRING:WSTRING", "wolf");
+ test.addTestCase("main.hurz_TIME:TIME", "PT1.234S");
+ test.addTestCase("main.hurz_LTIME:LTIME", "PT24015H23M12.034002044S");
+ test.addTestCase("main.hurz_DATE:DATE", "1978-03-28");
+ test.addTestCase("main.hurz_TIME_OF_DAY:TIME_OF_DAY", "15:36:30.123");
+ test.addTestCase("main.hurz_TOD:TOD", "16:17:18.123");
+ test.addTestCase("main.hurz_DATE_AND_TIME:DATE_AND_TIME", "1996-05-06T15:36:30");
+ test.addTestCase("main.hurz_DT:DT", "1972-03-29T00:00");
+ test.run();
}
}
diff --git a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualParserSerializerTest.java
similarity index 57%
copy from plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
copy to plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualParserSerializerTest.java
index 4685b74..f6dd3c2 100644
--- a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
+++ b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualParserSerializerTest.java
@@ -21,25 +21,13 @@ package org.apache.plc4x.protocol.ads;
import org.apache.commons.codec.binary.Hex;
import org.apache.plc4x.java.ads.readwrite.AmsTCPPacket;
import org.apache.plc4x.java.ads.readwrite.io.AmsTCPPacketIO;
-import org.apache.plc4x.java.api.PlcConnection;
import org.apache.plc4x.java.spi.generation.ReadBuffer;
-public class ManualAdsDriverTest {
+public class ManualParserSerializerTest {
public static void main(String[] args) throws Exception {
- // Working request:
- // 000050000000c0a8171401015303c0a817c80101feff09000400300000000000000002000000 81f0000002000000080000002000000006f00000000000000400000006f0000000000000040000000300801b3702001b
- // Working response:
- // 000030000000c0a817cd0101feffc0a81714010153030900050010000000000000000100000000000000080000000000000000000000
-
- // PLC4X request:
- // 000050000000c0a8171401015303c0a817c80101feff09000400300000000000000002000000 80f0000002000000020000002000000005f000000000801d010000000000000005f000003702001d0100000000000000
- // PLC4X response:
- // 000028000000c0a817c80101feffc0a8171401015303090005000800000000000000020000000507000000000000
-
-
-
- byte[] data = Hex.decodeHex("000028000000c0a817c80101feffc0a8171401015303090005000800000000000000010000000507000000000000");
+ byte[] data = Hex.decodeHex("0000f1000000c0a817c80101feffc0a817140101530309000500d1000000000000002f00000000000000c90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012a00a07d0f7e1c8e31489f8cf1006b3604b888defc88f64eb6fbb217d11fc5cf5f148b0abf05407c941a93b8263301db0f4940d66875727a0000000000d2040000ab6459032bbf7e03b888defcb8a5b249044de82ee03a2ab [...]
+ //byte[] data = Hex.decodeHex("0000f1000000c0a817c80101feffc0a817140101530309000500d1000000000000002f00000000000000c90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012a00a07d0f7e1c8e31489f8cf1006b3604b888defc");
ReadBuffer readBuffer = new ReadBuffer(data, true);
final AmsTCPPacket amsTCPPacket = AmsTCPPacketIO.staticParse(readBuffer);
System.out.println(amsTCPPacket);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 57ef551..1beef09 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -126,7 +126,8 @@ public class ReadBuffer {
}
try {
if (littleEndian) {
- return (Integer.reverseBytes(bi.readInt(true, bitLength)) >> 16) & 0xFFFF;
+ int intValue = bi.readInt(true, bitLength);
+ return Integer.reverseBytes(intValue) >>> 16;
}
return bi.readInt(true, bitLength);
} catch (IOException e) {
@@ -143,7 +144,8 @@ public class ReadBuffer {
}
try {
if (littleEndian) {
- return Long.reverseBytes(bi.readLong(true, bitLength)) >> 32;
+ final long longValue = bi.readLong(true, bitLength);
+ return Long.reverseBytes(longValue) >>> 32;
}
return bi.readLong(true, bitLength);
} catch (IOException e) {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
index ace32d3..26bfe38 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadRequest.java
@@ -44,6 +44,7 @@ import java.util.stream.Collectors;
public class DefaultPlcReadRequest implements PlcReadRequest, PlcFieldRequest, XmlSerializable {
private final PlcReader reader;
+ // This is intentionally a linked hash map in order to keep the order of how elements were added.
private LinkedHashMap<String, PlcField> fields;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
@@ -135,7 +136,7 @@ public class DefaultPlcReadRequest implements PlcReadRequest, PlcFieldRequest, X
public Builder(PlcReader reader, PlcFieldHandler fieldHandler) {
this.reader = reader;
this.fieldHandler = fieldHandler;
- fields = new TreeMap<>();
+ fields = new LinkedHashMap<>();
}
@Override
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBitString.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBitString.java
new file mode 100644
index 0000000..3550816
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcBitString.java
@@ -0,0 +1,61 @@
+/*
+ * 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.spi.values;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.value.PlcValue;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
+public class PlcBitString extends PlcList {
+
+ public PlcBitString(short byteBitString) {
+ super(toBitString(BigInteger.valueOf(byteBitString), 8));
+ }
+
+ public PlcBitString(int wordBitString) {
+ super(toBitString(BigInteger.valueOf(wordBitString), 16));
+ }
+
+ public PlcBitString(long dwordBitString) {
+ super(toBitString(BigInteger.valueOf(dwordBitString), 32));
+ }
+
+ public PlcBitString(BigInteger lwordBitString) {
+ super(toBitString(lwordBitString, 64));
+ }
+
+ public static List<PlcValue> toBitString(BigInteger bigInteger, int numBits) {
+ if(bigInteger.bitCount() > numBits) {
+ throw new PlcRuntimeException("value too big");
+ }
+ // Convert the numeric value into an array of bits.
+ List<PlcValue> values = new ArrayList<>(numBits);
+ for (int i = numBits - 1; i >= 0; i--) {
+ values.add(new PlcBOOL(bigInteger.testBit(i)));
+ }
+ return values;
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME_OF_DAY.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME_OF_DAY.java
index f415ad8..4f59c74 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME_OF_DAY.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME_OF_DAY.java
@@ -26,7 +26,6 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.w3c.dom.Element;
-import java.time.Duration;
import java.time.LocalTime;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
@@ -48,7 +47,7 @@ public class PlcTIME_OF_DAY extends PlcSimpleValue<LocalTime> {
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public PlcTIME_OF_DAY(@JsonProperty("value") Long value) {
- super(LocalTime.ofSecondOfDay(value / 1000), true);
+ super(LocalTime.ofNanoOfDay(value * 1000000), true);
}
@Override
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
new file mode 100644
index 0000000..c9110ec
--- /dev/null
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
@@ -0,0 +1,144 @@
+/*
+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.test.manual;
+
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.spi.values.PlcList;
+import org.junit.jupiter.api.Assertions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class ManualTest {
+
+ private final String connectionString;
+ private final List<TestCase> testCases;
+
+ public ManualTest(String connectionString) {
+ this.connectionString = connectionString;
+ testCases = new ArrayList<>();
+ }
+
+ public void addTestCase(String address, Object expectedValue) {
+ testCases.add(new TestCase(address, expectedValue));
+ }
+
+ public void run() throws Exception {
+ try (PlcConnection plcConnection = new PlcDriverManager().getConnection(connectionString)) {
+ System.out.println("Reading all types in separate requests");
+ // Run all entries separately:
+ for (TestCase testCase : testCases) {
+ String fieldName = testCase.address;
+ // Prepare the read-request
+ final PlcReadRequest readRequest = plcConnection.readRequestBuilder().addItem(fieldName, testCase.address).build();
+
+ // Execute the read request
+ final PlcReadResponse readResponse = readRequest.execute().get();
+
+ // Check the result
+ Assertions.assertEquals(1, readResponse.getFieldNames().size());
+ Assertions.assertEquals(fieldName, readResponse.getFieldNames().iterator().next());
+ Assertions.assertEquals(PlcResponseCode.OK, readResponse.getResponseCode(fieldName));
+ Assertions.assertNotNull(readResponse.getPlcValue(fieldName));
+ if(readResponse.getPlcValue(fieldName) instanceof PlcList) {
+ PlcList plcList = (PlcList) readResponse.getPlcValue(fieldName);
+ List<Object> expectedValues = (List<Object>) testCase.expectedValue;
+ for (int j = 0; j < expectedValues.size(); j++) {
+ Assertions.assertEquals(expectedValues.get(j), plcList.getIndex(j).getObject());
+ }
+ } else {
+ Assertions.assertEquals(
+ testCase.expectedValue.toString(), readResponse.getPlcValue(fieldName).getObject().toString());
+ }
+ }
+ System.out.println("Success");
+
+
+ // Read all items in one big request.
+ // Shuffle the list of test cases and run the test 10 times.
+ System.out.println("Reading all items together in random order");
+ for (int i = 0; i < 100; i++) {
+ System.out.println(" - run number " + i + " of " + 100);
+ final List<TestCase> shuffledTestcases = new ArrayList<>(testCases);
+ Collections.shuffle(shuffledTestcases);
+
+ StringBuilder sb = new StringBuilder();
+ for (TestCase testCase : shuffledTestcases) {
+ sb.append(testCase.address).append(", ");
+ }
+ System.out.println(" using order: " + sb.toString());
+
+ final PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
+ for (TestCase testCase : shuffledTestcases) {
+ String fieldName = testCase.address;
+ builder.addItem(fieldName, testCase.address);
+ }
+ final PlcReadRequest readRequest = builder.build();
+
+ // Execute the read request
+ final PlcReadResponse readResponse = readRequest.execute().get();
+
+ // Check the result
+ Assertions.assertEquals(shuffledTestcases.size(), readResponse.getFieldNames().size());
+ for (TestCase testCase : shuffledTestcases) {
+ String fieldName = testCase.address;
+ Assertions.assertEquals(PlcResponseCode.OK, readResponse.getResponseCode(fieldName));
+ Assertions.assertNotNull(readResponse.getPlcValue(fieldName));
+ if(readResponse.getPlcValue(fieldName) instanceof PlcList) {
+ PlcList plcList = (PlcList) readResponse.getPlcValue(fieldName);
+ List<Object> expectedValues = (List<Object>) testCase.expectedValue;
+ for (int j = 0; j < expectedValues.size(); j++) {
+ Assertions.assertEquals(expectedValues.get(j), plcList.getIndex(j).getObject());
+ }
+ } else {
+ Assertions.assertEquals(
+ testCase.expectedValue.toString(), readResponse.getPlcValue(fieldName).getObject().toString());
+ }
+ }
+ }
+ System.out.println("Success");
+ }
+ }
+
+ public static class TestCase {
+ private final String address;
+ private final Object expectedValue;
+
+ public TestCase(String address, Object expectedValue) {
+ this.address = address;
+ this.expectedValue = expectedValue;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public Object getExpectedValue() {
+ return expectedValue;
+ }
+ }
+
+
+}
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index adcc785..508dcd0 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -400,16 +400,16 @@
// Bit-strings
// -----------------------------------------
// 1 byte
- ['IEC61131_BYTE' List
- [array bit 'value' count '8']
+ ['IEC61131_BYTE' BitString
+ [simple uint 8 'value']
]
// 2 byte (16 bit)
- ['IEC61131_WORD' List
- [array bit 'value' count '16']
+ ['IEC61131_WORD' BitString
+ [simple uint 16 'value']
]
// 4 byte (32 bit)
- ['IEC61131_DWORD' List
- [array bit 'value' count '32']
+ ['IEC61131_DWORD' BitString
+ [simple uint 32 'value']
]
// -----------------------------------------
@@ -464,10 +464,12 @@
// [simple string 16 'UTF-16' 'value']
]
['IEC61131_STRING' STRING
-// [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
+ [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
+ [reserved uint 32 '0x00000000']
]
['IEC61131_WSTRING' STRING
-// [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
+ [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
+ [reserved uint 64 '0x00000000']
]
// -----------------------------------------