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/08/10 12:02:15 UTC
[plc4x] 05/05: - Continued working on the new AMS/ADS driver
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit eded6d8750c756b88acb69a1269341871df79dfe
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Aug 10 14:02:00 2020 +0200
- Continued working on the new AMS/ADS driver
---
.../main/resources/protocols/amsads/amsads.mspec | 178 +++++++-
.../apache/plc4x/java/amsads/AMSADSPlcDriver.java | 13 +-
.../attic/connection/AdsTcpPlcConnection.java | 13 +-
.../amsads/attic/protocol/Ads2PayloadProtocol.java | 2 +-
.../attic/protocol/Payload2SerialProtocol.java | 4 +-
.../amsads/attic/protocol/Payload2TcpProtocol.java | 2 +-
.../amsads/attic/protocol/Plc4x2AdsProtocol.java | 15 +-
.../protocol/exception/AdsException.java | 2 +-
.../exception/AdsProtocolOverflowException.java | 2 +-
.../{ => attic}/protocol/util/DigestUtil.java | 2 +-
.../protocol/util/LittleEndianDecoder.java | 8 +-
.../protocol/util/LittleEndianEncoder.java | 42 +-
.../protocol/util/SingleMessageRateLimiter.java | 2 +-
.../java/amsads/{ => attic}/types/AdsDataType.java | 7 +-
.../amsads/configuration/AdsConfiguration.java | 2 +-
.../apache/plc4x/java/amsads/field/AdsField.java | 2 +-
.../plc4x/java/amsads/field/AdsFieldHandler.java | 101 +++--
.../plc4x/java/amsads/field/DirectAdsField.java | 5 +-
.../plc4x/java/amsads/field/SymbolicAdsField.java | 2 +-
.../java/amsads/model/AdsSubscriptionHandle.java | 2 +-
.../java/amsads/protocol/AdsProtocolLogic.java | 274 ++++++++++--
.../java/amsads/protocol/util/package-info.java | 22 -
.../plc4x/java/amsads/utils/StaticHelper.java | 37 ++
.../services/org.apache.plc4x.java.api.PlcDriver | 19 -
.../apache/plc4x/protocol/amsads/AdsDriverIT.java | 29 ++
...arserTest.java => AdsSerializerParserTest.java} | 4 +-
.../src/test/resources/testsuite/AdsDriverIT.xml | 463 +++++++++++++++++++++
27 files changed, 1062 insertions(+), 192 deletions(-)
diff --git a/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec b/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec
index e5131f4..69d7283 100644
--- a/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec
+++ b/protocols/amsads/src/main/resources/protocols/amsads/amsads.mspec
@@ -319,7 +319,7 @@
// 4 bytes Length of the data (in bytes) which should be written.
[implicit uint 32 'writeLength' '(COUNT(items) * 12) + COUNT(data)']
// Only if the indexGroup implies a sum-read response, will the indexOffset indicate the number of elements.
- [array AdsReadRequest 'items' COUNT '(indexGroup == ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.value) ? indexOffset : 0']
+ [array AdsReadWriteRequest 'items' COUNT '(indexGroup == ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.value) ? indexOffset : 0']
// n bytes Data which are written in the ADS device.
[array int 8 'data' count 'writeLength - (COUNT(items) * 12)']
]
@@ -352,6 +352,182 @@
[array int 8 'data' count 'sampleSize']
]
+[dataIo 'DataItem' [AdsDataType 'adsDataType']
+ [typeSwitch 'adsDataType'
+ // -----------------------------------------
+ // Bit
+ // -----------------------------------------
+ ['AdsDataType.BOOL' Boolean
+ [reserved uint 7 '0x00']
+ [simple bit 'value']
+ ]
+ ['AdsDataType.BIT' Boolean
+ [reserved uint 7 '0x00']
+ [simple bit 'value']
+ ]
+ ['AdsDataType.BIT8' Boolean
+ [reserved uint 7 '0x00']
+ [simple bit 'value']
+ ]
+
+ // -----------------------------------------
+ // Bit-strings
+ // -----------------------------------------
+ // 1 byte
+ ['AdsDataType.BYTE' List
+ [array bit 'value' count '8']
+ ]
+ ['AdsDataType.BITARR8' List
+ [array bit 'value' count '8']
+ ]
+ // 2 byte (16 bit)
+ ['AdsDataType.WORD' List
+ [array bit 'value' count '16']
+ ]
+ ['AdsDataType.BITARR16' List
+ [array bit 'value' count '16']
+ ]
+ // 4 byte (32 bit)
+ ['AdsDataType.DWORD' List
+ [array bit 'value' count '32']
+ ]
+ ['AdsDataType.BITARR32' List
+ [array bit 'value' count '32']
+ ]
+
+ // -----------------------------------------
+ // Integers
+ // -----------------------------------------
+ // 8 bit:
+ ['AdsDataType.SINT' Integer
+ [simple int 8 'value']
+ ]
+ ['AdsDataType.INT8' Integer
+ [simple int 8 'value']
+ ]
+ ['AdsDataType.USINT' Integer
+ [simple uint 8 'value']
+ ]
+ ['AdsDataType.UINT8' Integer
+ [simple uint 8 'value']
+ ]
+ // 16 bit:
+ ['AdsDataType.INT' Integer
+ [simple int 16 'value']
+ ]
+ ['AdsDataType.INT16' Integer
+ [simple int 16 'value']
+ ]
+ ['AdsDataType.UINT' Integer
+ [simple uint 16 'value']
+ ]
+ ['AdsDataType.UINT16' Integer
+ [simple uint 16 'value']
+ ]
+ // 32 bit:
+ ['AdsDataType.DINT' Integer
+ [simple int 32 'value']
+ ]
+ ['AdsDataType.INT32' Integer
+ [simple int 32 'value']
+ ]
+ ['AdsDataType.UDINT' Long
+ [simple uint 32 'value']
+ ]
+ ['AdsDataType.UINT32' Long
+ [simple uint 32 'value']
+ ]
+ // 64 bit:
+ ['AdsDataType.LINT' Long
+ [simple int 64 'value']
+ ]
+ ['AdsDataType.INT64' Long
+ [simple int 64 'value']
+ ]
+ ['AdsDataType.ULINT' BigInteger
+ [simple uint 64 'value']
+ ]
+ ['AdsDataType.UINT64' BigInteger
+ [simple uint 64 'value']
+ ]
+
+ // -----------------------------------------
+ // Floating point values
+ // -----------------------------------------
+ ['AdsDataType.REAL' Float
+ [simple float 8.23 'value']
+ ]
+ ['AdsDataType.FLOAT' Float
+ [simple float 8.23 'value']
+ ]
+ ['AdsDataType.LREAL' Double
+ [simple float 11.52 'value']
+ ]
+ ['AdsDataType.DOUBLE' Double
+ [simple float 11.52 'value']
+ ]
+
+ // -----------------------------------------
+ // Characters & Strings
+ // -----------------------------------------
+ ['AdsDataType.STRING' String
+// [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.amsads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.amsads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
+ ]
+ ]
+]
+
+[enum 'AdsDataType' [uint 8 'numBytes']
+ [BOOL ['1']]
+ [BIT ['1']]
+ [BIT8 ['1']]
+ // -----------------------------------------
+ // Bit-strings
+ // -----------------------------------------
+ // 1 byte
+ [BYTE ['1']]
+ [BITARR8 ['1']]
+ // 2 byte (16 bit)
+ [WORD ['2']]
+ [BITARR16 ['2']]
+ // 4 byte (32 bit)
+ [DWORD ['4']]
+ [BITARR32 ['4']]
+ // -----------------------------------------
+ // Integers
+ // -----------------------------------------
+ // 8 bit:
+ [SINT ['1']]
+ [INT8 ['1']]
+ [USINT ['1']]
+ [UINT8 ['1']]
+ // 16 bit:
+ [INT ['2']]
+ [INT16 ['2']]
+ [UINT ['2']]
+ [UINT16 ['2']]
+ // 32 bit:
+ [DINT ['4']]
+ [INT32 ['4']]
+ [UDINT ['4']]
+ [UINT32 ['4']]
+ // 64 bit:
+ [LINT ['8']]
+ [INT64 ['8']]
+ [ULINT ['8']]
+ [UINT64 ['8']]
+ // -----------------------------------------
+ // Floating point values
+ // -----------------------------------------
+ [REAL ['4']]
+ [FLOAT ['4']]
+ [LREAL ['8']]
+ [DOUBLE ['8']]
+ // -----------------------------------------
+ // Characters & Strings
+ // -----------------------------------------
+ [STRING ['9']]
+]
+
[enum uint 16 'ReservedIndexGroups'
['0xF000' ADSIGRP_SYMTAB]
['0xF001' ADSIGRP_SYMNAME]
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
index 4961373..55ee0dd 100644
--- 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
@@ -45,7 +45,17 @@ public class AMSADSPlcDriver extends GeneratedDriverBase<AmsPacket> {
@Override
public String getProtocolName() {
- return "Beckhoff Twincat ADS";
+ return "Beckhoff TwinCat ADS";
+ }
+
+ @Override
+ protected boolean canRead() {
+ return true;
+ }
+
+ @Override
+ protected boolean canWrite() {
+ return true;
}
@Override
@@ -67,6 +77,7 @@ public class AMSADSPlcDriver extends GeneratedDriverBase<AmsPacket> {
protected ProtocolStackConfigurer<AmsPacket> getStackConfigurer() {
return SingleProtocolStackConfigurer.builder(AmsPacket.class, AmsPacketIO.class)
.withProtocol(AdsProtocolLogic.class)
+ .littleEndian()
.build();
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java
index b69eb94..58f7af2 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/connection/AdsTcpPlcConnection.java
@@ -22,11 +22,11 @@ import org.apache.commons.lang3.tuple.Pair;
import org.apache.plc4x.java.amsads.field.AdsFieldHandler;
import org.apache.plc4x.java.amsads.field.DirectAdsField;
import org.apache.plc4x.java.amsads.field.SymbolicAdsField;
-import org.apache.plc4x.java.amsads.model.*;
import org.apache.plc4x.java.amsads.attic.protocol.Plc4x2AdsProtocol;
-import org.apache.plc4x.java.amsads.protocol.util.LittleEndianDecoder;
+import org.apache.plc4x.java.amsads.attic.protocol.util.LittleEndianDecoder;
+import org.apache.plc4x.java.amsads.model.AdsSubscriptionHandle;
import org.apache.plc4x.java.amsads.readwrite.*;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.apache.plc4x.java.api.messages.*;
@@ -46,7 +46,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
-import java.net.*;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
@@ -200,7 +203,7 @@ public class AdsTcpPlcConnection extends AdsAbstractPlcConnection implements Plc
AdsAddDeviceNotificationRequest adsAddDeviceNotificationRequest = new AdsAddDeviceNotificationRequest(
indexGroup,
indexOffset,
- adsDataType.getTargetByteSize() * (long) numberOfElements,
+ adsDataType.getNumBytes() * (long) numberOfElements,
transmissionMode,
cycleTime + 1,
cycleTime
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java
index a20ff7c..b583aba 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Ads2PayloadProtocol.java
@@ -22,7 +22,7 @@ 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.amsads.protocol.exception.AdsException;
+import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
import org.apache.plc4x.java.amsads.readwrite.AmsPacket;
import org.apache.plc4x.java.amsads.readwrite.io.AmsPacketIO;
import org.apache.plc4x.java.spi.generation.ParseException;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java
index 4092bbf..716b4f4 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2SerialProtocol.java
@@ -24,8 +24,8 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.util.concurrent.ScheduledFuture;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.amsads.protocol.exception.AdsException;
-import org.apache.plc4x.java.amsads.protocol.util.DigestUtil;
+import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
+import org.apache.plc4x.java.amsads.attic.protocol.util.DigestUtil;
import org.apache.plc4x.java.amsads.readwrite.AmsPacket;
import org.apache.plc4x.java.amsads.readwrite.AmsSerialFrame;
import org.apache.plc4x.java.amsads.readwrite.AmsTCPPacket;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java
index e719bf0..49f39b6 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Payload2TcpProtocol.java
@@ -22,7 +22,7 @@ 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.amsads.protocol.exception.AdsException;
+import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
import org.apache.plc4x.java.amsads.readwrite.AmsPacket;
import org.apache.plc4x.java.amsads.readwrite.AmsTCPPacket;
import org.apache.plc4x.java.amsads.readwrite.io.AmsPacketIO;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java
index 3d12b7a..8f9946e 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/Plc4x2AdsProtocol.java
@@ -20,12 +20,12 @@ package org.apache.plc4x.java.amsads.attic.protocol;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
import org.apache.plc4x.java.amsads.field.AdsField;
import org.apache.plc4x.java.amsads.field.DirectAdsField;
import org.apache.plc4x.java.amsads.field.SymbolicAdsField;
-import org.apache.plc4x.java.amsads.protocol.exception.AdsException;
+import org.apache.plc4x.java.amsads.attic.protocol.exception.AdsException;
import org.apache.plc4x.java.amsads.readwrite.*;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.amsads.readwrite.types.CommandId;
import org.apache.plc4x.java.api.exceptions.PlcException;
import org.apache.plc4x.java.api.exceptions.PlcIoException;
@@ -53,8 +53,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import static org.apache.plc4x.java.amsads.protocol.util.LittleEndianDecoder.decodeData;
-import static org.apache.plc4x.java.amsads.protocol.util.LittleEndianEncoder.encodeData;
+import static org.apache.plc4x.java.amsads.attic.protocol.util.LittleEndianDecoder.decodeData;
@Deprecated
public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcRequestContainer<InternalPlcRequest, InternalPlcResponse>> {
@@ -160,9 +159,9 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
plcValues[0] = plcValue.getObject();
}
- byte[] bytes = encodeData(directAdsField.getAdsDataType(), plcValues);
+ byte[] bytes = null;//encodeData(directAdsField.getAdsDataType(), plcValues);
int bytesToBeWritten = bytes.length;
- int maxTheoreticalSize = directAdsField.getAdsDataType().getTargetByteSize() * directAdsField.getNumberOfElements();
+ int maxTheoreticalSize = directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements();
if (bytesToBeWritten > maxTheoreticalSize) {
LOGGER.debug("Requested AdsDatatype {} is exceeded by number of bytes {}. Limit {}.", directAdsField.getAdsDataType(), bytesToBeWritten, maxTheoreticalSize);
throw new PlcProtocolPayloadTooBigException("ADS", maxTheoreticalSize, bytesToBeWritten, plcValues);
@@ -198,8 +197,8 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque
long indexOffset = directAdsField.getIndexOffset();
AdsDataType adsDataType = directAdsField.getAdsDataType();
int numberOfElements = directAdsField.getNumberOfElements();
- int readLength = adsDataType.getTargetByteSize() * numberOfElements;
- AdsReadWriteRequest data = new AdsReadWriteRequest(indexGroup, indexOffset, readLength, new AdsReadRequest[0], new byte[0]);
+ int readLength = adsDataType.getNumBytes() * numberOfElements;
+ AdsReadWriteRequest data = new AdsReadWriteRequest(indexGroup, indexOffset, readLength, new AdsReadWriteRequest[0], new byte[0]);
AmsPacket amsPacket = new AmsPacket(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort, CommandId.ADS_READ, new State(false, false, false, false, false, false, true, false, false), 0, invokeId, data);
LOGGER.debug("encoded read request {}", amsPacket);
out.add(amsPacket);
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsException.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java
similarity index 96%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsException.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java
index 909ecc1..249ca9f 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsException.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsException.java
@@ -16,7 +16,7 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.exception;
+package org.apache.plc4x.java.amsads.attic.protocol.exception;
import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsProtocolOverflowException.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java
similarity index 95%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsProtocolOverflowException.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java
index 023b467..d81bece 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/exception/AdsProtocolOverflowException.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/exception/AdsProtocolOverflowException.java
@@ -17,7 +17,7 @@
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.exception;
+package org.apache.plc4x.java.amsads.attic.protocol.exception;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/DigestUtil.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java
similarity index 96%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/DigestUtil.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java
index b3e9a62..753b9ee 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/DigestUtil.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/DigestUtil.java
@@ -16,7 +16,7 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.util;
+package org.apache.plc4x.java.amsads.attic.protocol.util;
import com.github.snksoft.crc.CRC;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianDecoder.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java
similarity index 99%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianDecoder.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java
index cd3d554..cdff936 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianDecoder.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianDecoder.java
@@ -16,13 +16,13 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.util;
+package org.apache.plc4x.java.amsads.attic.protocol.util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.NotImplementedException;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
import org.apache.plc4x.java.api.value.*;
@@ -410,7 +410,7 @@ public class LittleEndianDecoder {
return new PlcList(values);
}
}
- case TIME: {
+/* case TIME: {
LinkedList<Long> values = new LinkedList<>();
while (wrappedBuffer.isReadable()) {
long aByte = wrappedBuffer.readUnsignedIntLE();
@@ -480,7 +480,7 @@ public class LittleEndianDecoder {
case SUB_RANGE_DATA_TYPE: {
throw new NotImplementedException("not implemented yet " + adsDataType);
}
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcUnsupportedDataTypeException("Unsupported adsDataType " + adsDataType);
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianEncoder.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java
similarity index 89%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianEncoder.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java
index 620a551..d3ccad4 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/LittleEndianEncoder.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/LittleEndianEncoder.java
@@ -16,10 +16,10 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.util;
+package org.apache.plc4x.java.amsads.attic.protocol.util;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
import org.apache.plc4x.java.api.exceptions.PlcProtocolPayloadTooBigException;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
@@ -110,8 +110,8 @@ public class LittleEndianEncoder {
// TODO: add boundchecks and add optional extension
return byteArrayStream
.peek(bytes -> {
- if (bytes.length > adsDataType.getTargetByteSize()) {
- throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getTargetByteSize(), bytes.length, bytes));
+ if (bytes.length > adsDataType.getNumBytes()) {
+ throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getNumBytes(), bytes.length, bytes));
}
});
}
@@ -120,8 +120,8 @@ public class LittleEndianEncoder {
// TODO: add boundchecks and add optional extension
return byteArrayStream.map(ArrayUtils::toPrimitive)
.peek(bytes -> {
- if (bytes.length > adsDataType.getTargetByteSize()) {
- throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getTargetByteSize(), bytes.length, bytes));
+ if (bytes.length > adsDataType.getNumBytes()) {
+ throw new PlcRuntimeException(new PlcProtocolPayloadTooBigException("ads", adsDataType.getNumBytes(), bytes.length, bytes));
}
});
}
@@ -137,7 +137,7 @@ public class LittleEndianEncoder {
(byte) ((intValue & 0x00ff0000) >> 16),
(byte) ((intValue & 0xff000000) >> 24),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeDouble(AdsDataType adsDataType, Stream<Double> doubleStream) {
@@ -155,7 +155,7 @@ public class LittleEndianEncoder {
(byte) ((longValue & 0x00ff0000_00000000L) >> 48),
(byte) ((longValue & 0xff000000_00000000L) >> 56),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeInteger(AdsDataType adsDataType, Stream<Integer> integerStream) {
@@ -167,7 +167,7 @@ public class LittleEndianEncoder {
(byte) ((intValue & 0x00ff0000) >> 16),
(byte) ((intValue & 0xff000000) >> 24),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeLong(AdsDataType adsDataType, Stream<Long> longStream) {
@@ -183,7 +183,7 @@ public class LittleEndianEncoder {
(byte) ((longValue & 0x00ff0000_00000000L) >> 48),
(byte) ((longValue & 0xff000000_00000000L) >> 56),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeBigInteger(AdsDataType adsDataType, Stream<BigInteger> bigIntegerStream) {
@@ -192,15 +192,15 @@ public class LittleEndianEncoder {
.map(bigIntValue -> {
byte[] bytes = bigIntValue.toByteArray();
if (bytes.length > 1 && bytes[0] == 0x0) {
- byte[] subArray = Arrays.copyOf(ArrayUtils.subarray(bytes, 1, bytes.length), adsDataType.getTargetByteSize());
+ byte[] subArray = Arrays.copyOf(ArrayUtils.subarray(bytes, 1, bytes.length), adsDataType.getNumBytes());
ArrayUtils.reverse(subArray);
return subArray;
} else {
- ArrayUtils.reverse(Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ ArrayUtils.reverse(Arrays.copyOf(bytes, adsDataType.getNumBytes()));
return bytes;
}
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeLocalTime(AdsDataType adsDataType, Stream<LocalTime> localTimeStream) {
@@ -214,7 +214,7 @@ public class LittleEndianEncoder {
(byte) ((time & 0x00000000_00ff0000L) >> 16),
(byte) ((time & 0x00000000_ff000000L) >> 24),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeLocalDate(AdsDataType adsDataType, Stream<LocalDate> localDateStream) {
@@ -230,7 +230,7 @@ public class LittleEndianEncoder {
(byte) ((time & 0x00000000_00ff0000L) >> 16),
(byte) ((time & 0x00000000_ff000000L) >> 24),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeLocalDateTime(AdsDataType adsDataType, Stream<LocalDateTime> localDateTimeStream) {
@@ -250,7 +250,7 @@ public class LittleEndianEncoder {
(byte) ((time & 0x00ff0000_00000000L) >> 48),
(byte) ((time & 0xff000000_00000000L) >> 56),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
@@ -261,25 +261,25 @@ public class LittleEndianEncoder {
(byte) (shortValue & 0x00ff),
(byte) ((shortValue & 0xff00) >> 8),
})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeByte(AdsDataType adsDataType, Stream<Byte> byteStream) {
return byteStream
.peek(value -> checkBound(adsDataType, value))
.map(aByte -> new byte[]{aByte})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static Stream<byte[]> encodeBoolean(AdsDataType adsDataType, Stream<Boolean> booleanStream) {
return booleanStream
.map(booleanValue -> new byte[]{booleanValue ? (byte) 0x01 : (byte) 0x00})
- .map(bytes -> Arrays.copyOf(bytes, adsDataType.getTargetByteSize()));
+ .map(bytes -> Arrays.copyOf(bytes, adsDataType.getNumBytes()));
}
private static void checkBound(AdsDataType adsDataType, double other) {
- if (!adsDataType.withinBounds(other)) {
+ /*if (!adsDataType.withinBounds(other)) {
throw new PlcRuntimeException(other + " not within bounds of " + adsDataType);
- }
+ }*/
}
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/SingleMessageRateLimiter.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java
similarity index 98%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/SingleMessageRateLimiter.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java
index 90e8ecd..79de06c 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/SingleMessageRateLimiter.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/protocol/util/SingleMessageRateLimiter.java
@@ -16,7 +16,7 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.protocol.util;
+package org.apache.plc4x.java.amsads.attic.protocol.util;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/types/AdsDataType.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java
similarity index 98%
rename from sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/types/AdsDataType.java
rename to sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java
index 07a4f23..8b2a99e 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/types/AdsDataType.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/attic/types/AdsDataType.java
@@ -16,7 +16,7 @@
specific language governing permissions and limitations
under the License.
*/
-package org.apache.plc4x.java.amsads.types;
+package org.apache.plc4x.java.amsads.attic.types;
import org.apache.commons.lang3.ArrayUtils;
@@ -37,8 +37,9 @@ import java.util.stream.IntStream;
* @see <a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tcplccontrol/html/tcplcctrl_plc_data_types_overview.htm&id">TwinCAT PLC Control: Data Types</a>
*/
public enum AdsDataType {
- // TODO: maybe this are just types for the plc ide and can be removed
- // https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=
+ // System-Manager versions of the IEC61131-3 datatypes.
+ // See: https://infosys.beckhoff.com/english.php?content=../content/1033/tcsystemmanager/basics/TcSysMgr_DatatypeComparison.htm&id=
+ // For mapping
BIT(0, 1, 8),
BIT8((short) 0x00, (short) 0xFF, 8),
BITARR8((short) 0x00, (short) 0xFF, 8),
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/configuration/AdsConfiguration.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/configuration/AdsConfiguration.java
index 8919d38..5a01e54 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/configuration/AdsConfiguration.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/configuration/AdsConfiguration.java
@@ -141,7 +141,7 @@ public class AdsConfiguration implements Configuration, TcpTransportConfiguratio
}
String[] split = address.split("\\.");
short[] shorts = ArrayUtils.toPrimitive(Stream.of(split).map(Integer::parseInt).map(Integer::shortValue).toArray(Short[]::new));
- return new AmsNetId(shorts[5], shorts[4], shorts[3], shorts[2], shorts[1], shorts[0]);
+ return new AmsNetId(shorts[0], shorts[1], shorts[2], shorts[3], shorts[4], shorts[5]);
}
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsField.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsField.java
index 4bbf0e4..9c16181 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsField.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsField.java
@@ -18,7 +18,7 @@
*/
package org.apache.plc4x.java.amsads.field;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.model.PlcField;
@FunctionalInterface
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsFieldHandler.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsFieldHandler.java
index ce81453..21ffa4a 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsFieldHandler.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/AdsFieldHandler.java
@@ -18,7 +18,7 @@
*/
package org.apache.plc4x.java.amsads.field;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.apache.plc4x.java.api.model.PlcField;
@@ -87,7 +87,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -98,7 +98,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeBoolean(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -138,7 +138,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -149,7 +149,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeInteger(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -189,7 +189,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -200,7 +200,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeInteger(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -240,7 +240,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -251,7 +251,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeInteger(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -291,7 +291,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -302,7 +302,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeInteger(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -342,7 +342,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -353,7 +353,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeInteger(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -393,7 +393,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -404,7 +404,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeFloatingPoint(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -444,7 +444,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -455,7 +455,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeFloatingPoint(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -495,7 +495,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -506,7 +506,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalEncodeString(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -546,7 +546,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -557,7 +557,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalTimeTemporal(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -597,7 +597,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -608,7 +608,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalDateTemporal(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -648,7 +648,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case REAL:
case LREAL:
case STRING:
- case TIME:
+ /*case TIME:
case TIME_OF_DAY:
case DATE:
case DATE_AND_TIME:
@@ -659,7 +659,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
case ALIAS:
case SUB_RANGE_DATA_TYPE:
return internalDateTimeTemporal(field, values);
- case UNKNOWN:
+ case UNKNOWN:*/
default:
throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name());
}
@@ -777,9 +777,9 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
}
Number value = (Number) values[i];
- if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+/* if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
- }
+ }*/
longValues[i] = value.longValue();
}
if(longValues.length == 1) {
@@ -801,9 +801,9 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
"Value of type " + values[i].getClass().getName() +
" is not assignable to " + adsField.getAdsDataType().name() + " fields.");
}
- if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
+/* if (!adsField.getAdsDataType().withinBounds(value.doubleValue())) {
throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsField.getAdsDataType());
- }
+ }*/
bigIntegerValues[i] = value.toBigInteger();
}
if(bigIntegerValues.length == 1) {
@@ -843,9 +843,9 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
}
Number value = (Number) values[i];
- if (!adsDataType.withinBounds(value.doubleValue())) {
+/* if (!adsDataType.withinBounds(value.doubleValue())) {
throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsDataType);
- }
+ }*/
}
if(floatingPointValues.length == 1) {
return new PlcDouble(floatingPointValues[0]);
@@ -857,11 +857,11 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
for (int i = 0; i < values.length; i++) {
if (values[i] instanceof Double) {
Double aDouble = (Double) values[i];
- if (!adsDataType.withinBounds(aDouble)) {
+/* if (!adsDataType.withinBounds(aDouble)) {
throw new IllegalArgumentException(
"Value of " + aDouble + " exceeds allowed minimum for type "
+ adsDataType.name() + " (min " + adsDataType.getLowerBound() + "/max +" + adsDataType.getUpperBound() + ")");
- }
+ }*/
floatingPointValues[i] = aDouble.floatValue();
} else if (values[i] instanceof Float) {
floatingPointValues[i] = (Float) values[i];
@@ -872,9 +872,9 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
}
Number value = (Number) values[i];
- if (!adsDataType.withinBounds(value.doubleValue())) {
+/* if (!adsDataType.withinBounds(value.doubleValue())) {
throw new IllegalArgumentException("Value " + values[i] + " ist not within bounds of " + adsDataType);
- }
+ }*/
}
if(floatingPointValues.length == 1) {
return new PlcFloat(floatingPointValues[0]);
@@ -886,7 +886,7 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
private PlcValue internalEncodeString(PlcField field, Object[] values) {
AdsField adsField = (AdsField) field;
- Number maxLength = adsField.getAdsDataType().getUpperBound();
+// Number maxLength = adsField.getAdsDataType().getUpperBound();
//boolean encoding16Bit;
switch (adsField.getAdsDataType()) {
case STRING:
@@ -900,11 +900,11 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
for (Object value : values) {
if (value instanceof String) {
String stringValue = (String) value;
- if (stringValue.length() > maxLength.intValue()) {
+/* if (stringValue.length() > maxLength.intValue()) {
throw new IllegalArgumentException(
"String length " + stringValue.length() + " exceeds allowed maximum for type "
+ adsField.getAdsDataType().name() + " (max " + maxLength + ")");
- }
+ }*/
stringValues.add(stringValue);
}
// All other types just translate to max one String character.
@@ -970,16 +970,16 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
private PlcValue internalTimeTemporal(PlcField field, Object[] values) {
AdsField adsField = (AdsField) field;
switch (adsField.getAdsDataType()) {
- case TIME:
+/* case TIME:
case DATE:
case DATE_AND_TIME:
- break;
+ break;*/
default:
throw new IllegalArgumentException(
"Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields.");
}
// TODO: support other types
- List<LocalTime> localTimeValues = Arrays.stream(values)
+ /*List<LocalTime> localTimeValues = Arrays.stream(values)
.filter(LocalTime.class::isInstance)
.map(LocalTime.class::cast)
.collect(Collectors.toList());
@@ -987,22 +987,22 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
return new PlcTime(localTimeValues.get(0));
} else {
return new PlcList(localTimeValues);
- }
+ }*/
}
private PlcValue internalDateTemporal(PlcField field, Object[] values) {
AdsField adsField = (AdsField) field;
switch (adsField.getAdsDataType()) {
- case TIME:
+/* case TIME:
case DATE:
case DATE_AND_TIME:
- break;
+ break;*/
default:
throw new IllegalArgumentException(
"Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields.");
}
// TODO: support other types
- List<LocalDate> localDateValues = Arrays.stream(values)
+ /*List<LocalDate> localDateValues = Arrays.stream(values)
.filter(LocalDate.class::isInstance)
.map(LocalDate.class::cast)
.collect(Collectors.toList());
@@ -1010,14 +1010,14 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
return new PlcDate(localDateValues.get(0));
} else {
return new PlcList(localDateValues);
- }
+ }*/
}
private PlcValue internalDateTimeTemporal(PlcField field, Object[] values) {
AdsField adsField = (AdsField) field;
Class<? extends PlcValue> fieldType;
switch (adsField.getAdsDataType()) {
- case TIME:
+/* case TIME:
fieldType = PlcTime.class;
break;
case DATE:
@@ -1025,12 +1025,12 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
break;
case DATE_AND_TIME:
fieldType = PlcDateTime.class;
- break;
+ break;*/
default:
throw new IllegalArgumentException(
"Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields.");
}
- if(values.length == 1) {
+ /*if(values.length == 1) {
// TODO: add type conversion
if (fieldType == PlcTime.class) {
return new PlcTime((LocalTime) values[0]);
@@ -1041,7 +1041,6 @@ public class AdsFieldHandler extends DefaultPlcFieldHandler {
}
} else {
return new PlcList(Arrays.asList(values));
- }
-
+ }*/
}
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/DirectAdsField.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/DirectAdsField.java
index 475a97c..0db8d34 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/DirectAdsField.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/DirectAdsField.java
@@ -18,8 +18,7 @@
*/
package org.apache.plc4x.java.amsads.field;
-//import org.apache.plc4x.java.ads.api.util.ByteValue;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
import java.util.Objects;
@@ -42,7 +41,7 @@ public class DirectAdsField implements AdsField {
private final int numberOfElements;
- private DirectAdsField(long indexGroup, long indexOffset, AdsDataType adsDataType, Integer numberOfElements) {
+ public DirectAdsField(long indexGroup, long indexOffset, AdsDataType adsDataType, Integer numberOfElements) {
//ByteValue.checkUnsignedBounds(indexGroup, 4);
this.indexGroup = indexGroup;
//ByteValue.checkUnsignedBounds(indexOffset, 4);
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/SymbolicAdsField.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/SymbolicAdsField.java
index d6ab98e..c4edfce 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/SymbolicAdsField.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/field/SymbolicAdsField.java
@@ -18,7 +18,7 @@
*/
package org.apache.plc4x.java.amsads.field;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
import java.util.Objects;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/model/AdsSubscriptionHandle.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/model/AdsSubscriptionHandle.java
index 883ce25..1a0f60e 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/model/AdsSubscriptionHandle.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/model/AdsSubscriptionHandle.java
@@ -18,7 +18,7 @@ under the License.
*/
package org.apache.plc4x.java.amsads.model;
-import org.apache.plc4x.java.amsads.types.AdsDataType;
+import org.apache.plc4x.java.amsads.readwrite.types.AdsDataType;
import org.apache.plc4x.java.spi.messages.PlcSubscriber;
import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionHandle;
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AdsProtocolLogic.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AdsProtocolLogic.java
index 8ecba8f..ad67193 100644
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AdsProtocolLogic.java
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/AdsProtocolLogic.java
@@ -22,6 +22,7 @@ import org.apache.plc4x.java.amsads.configuration.AdsConfiguration;
import org.apache.plc4x.java.amsads.field.DirectAdsField;
import org.apache.plc4x.java.amsads.field.SymbolicAdsField;
import org.apache.plc4x.java.amsads.readwrite.*;
+import org.apache.plc4x.java.amsads.readwrite.io.DataItemIO;
import org.apache.plc4x.java.amsads.readwrite.types.CommandId;
import org.apache.plc4x.java.amsads.readwrite.types.ReservedIndexGroups;
import org.apache.plc4x.java.api.messages.PlcReadRequest;
@@ -29,32 +30,42 @@ 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.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.api.value.*;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.Plc4xProtocolBase;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
+import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
+import org.apache.plc4x.java.spi.messages.InternalPlcReadRequest;
+import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements HasConfiguration<AdsConfiguration> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AdsProtocolLogic.class);
+
private AdsConfiguration configuration;
public static final State DEFAULT_COMMAND_STATE = new State(
- false, false, false, false, false, false, true, false, false);
+ false, false, false, false, false, true, false, false, false);
private ConversationContext<AmsPacket> adsDriverContext;
- private static final AtomicLong invokeIdGenerator = new AtomicLong(0);
+ private final AtomicLong invokeIdGenerator = new AtomicLong(1);
private RequestTransactionManager tm;
private ConcurrentHashMap<SymbolicAdsField, DirectAdsField> symbolicFieldMapping;
- private ConcurrentHashMap<SymbolicAdsField, CompletableFuture<DirectAdsField>> pendingResolutionRequests;
+ private ConcurrentHashMap<SymbolicAdsField, CompletableFuture<Void>> pendingResolutionRequests;
public AdsProtocolLogic() {
symbolicFieldMapping = new ConcurrentHashMap<>();
@@ -104,7 +115,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
final List<DirectAdsField> directAdsFields = getDirectAddresses(readRequest.getFields());
// Depending on the number of fields, use a single item request or a sum-request
- if(directAdsFields.size() == 1) {
+ if (directAdsFields.size() == 1) {
// Do a normal (single item) ADS Read Request
return singleRead(readRequest, directAdsFields.get(0));
} else {
@@ -116,7 +127,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
protected CompletableFuture<PlcReadResponse> singleRead(PlcReadRequest readRequest, DirectAdsField directAdsField) {
CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
- int size = directAdsField.getAdsDataType().getTargetByteSize() * directAdsField.getNumberOfElements();
+ int size = directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements();
AdsData adsData = new AdsReadRequest(directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), size);
AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
@@ -146,17 +157,16 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
// Calculate the size of all fields together.
int size = 0;
- // TODO: Add the items ...
- List<AdsReadRequest> items = new ArrayList<>(directAdsFields.size());
-
// With multi-requests, the index-group is fixed and the index offset indicates the number of elements.
AdsData adsData = new AdsReadWriteRequest(
ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), directAdsFields.size(), size,
- items.toArray(new AdsReadRequest[0]), new byte[0]);
+ directAdsFields.stream().map(directAdsField -> new AdsReadWriteRequest(
+ directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), directAdsField.getNumberOfElements(),
+ new AdsReadWriteRequest[0], new byte[0])).toArray(AdsReadWriteRequest[]::new), new byte[0]);
AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
- CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, invokeIdGenerator.getAndIncrement(), adsData);
+ CommandId.ADS_READ_WRITE, DEFAULT_COMMAND_STATE, 0, invokeIdGenerator.getAndIncrement(), adsData);
// Start a new request-transaction (Is ended in the response-handler)
RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
@@ -177,9 +187,78 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
}
protected PlcReadResponse convertToPlc4xReadResponse(PlcReadRequest readRequest, AdsData adsData) {
+ ReadBuffer readBuffer = null;
+ Map<String, PlcResponseCode> responseCodes = new HashMap<>();
+ if (adsData instanceof AdsReadResponse) {
+ AdsReadResponse adsReadResponse = (AdsReadResponse) adsData;
+ readBuffer = new ReadBuffer(adsReadResponse.getData());
+ responseCodes.put(readRequest.getFieldNames().stream().findFirst().orElse(""),
+ parsePlcResponseCode(adsReadResponse.getResult()));
+ } else if (adsData instanceof AdsReadWriteResponse) {
+ AdsReadWriteResponse adsReadWriteResponse = (AdsReadWriteResponse) adsData;
+ readBuffer = new ReadBuffer(adsReadWriteResponse.getData());
+ // When parsing a multi-item response, the error codes of each items come
+ // in sequence and then come the values.
+ for (String fieldName : readRequest.getFieldNames()) {
+ try {
+ final long result = readBuffer.readUnsignedLong(32);
+ responseCodes.put(fieldName, parsePlcResponseCode(result));
+ } catch (ParseException e) {
+ responseCodes.put(fieldName, PlcResponseCode.INTERNAL_ERROR);
+ }
+ }
+ }
+ if(readBuffer != null) {
+ Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
+ for (String fieldName : readRequest.getFieldNames()) {
+ DirectAdsField directAdsField = (DirectAdsField) readRequest.getField(fieldName);
+ // If the response-code was anything but OK, we don't need to parse the payload.
+ if(responseCodes.get(fieldName) != PlcResponseCode.OK) {
+ values.put(fieldName, new ResponseItem<>(responseCodes.get(fieldName), null));
+ }
+ // If the response-code was ok, parse the data returned.
+ else {
+ values.put(fieldName, parsePlcValue(directAdsField, readBuffer));
+ }
+ }
+ return new DefaultPlcReadResponse((InternalPlcReadRequest) readRequest, values);
+ }
return null;
}
+ private PlcResponseCode parsePlcResponseCode(long adsResult) {
+ if (adsResult == 0L) {
+ return PlcResponseCode.OK;
+ } else {
+ // TODO: Implement this a little more ...
+ return PlcResponseCode.INTERNAL_ERROR;
+ }
+ }
+
+ private ResponseItem<PlcValue> parsePlcValue(DirectAdsField field, ReadBuffer readBuffer) {
+ try {
+ if (field.getNumberOfElements() == 1) {
+ return new ResponseItem<>(PlcResponseCode.OK,
+ DataItemIO.staticParse(readBuffer, field.getAdsDataType()));
+ } else {
+ // Fetch all
+ final PlcValue[] resultItems = IntStream.range(0, field.getNumberOfElements()).mapToObj(i -> {
+ try {
+ return DataItemIO.staticParse(readBuffer, field.getAdsDataType());
+ } catch (ParseException e) {
+ LOGGER.warn("Error parsing field item of type: '{}' (at position {}})", field.getAdsDataType(), i, e);
+ }
+ return null;
+ }).toArray(PlcValue[]::new);
+ return new ResponseItem<>(PlcResponseCode.OK, PlcValues.of(resultItems));
+ }
+ } catch (ParseException e) {
+ LOGGER.warn(String.format("Error parsing field item of type: '%s'", field.getAdsDataType()), e);
+ return new ResponseItem<>(PlcResponseCode.INTERNAL_ERROR, null);
+ }
+ }
+
+
@Override
public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
return super.write(writeRequest);
@@ -199,34 +278,43 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
// Find out for which of these symbolic addresses no resolution has been initiated.
final List<SymbolicAdsField> symbolicFieldsNeedingResolution = referencedSymbolicFields.stream()
- .filter(symbolicAdsField -> symbolicFieldMapping.containsKey(symbolicAdsField))
+ .filter(symbolicAdsField -> !symbolicFieldMapping.containsKey(symbolicAdsField))
.collect(Collectors.toList());
// If there are unresolved symbolic addresses, initiate the resolution
- if(!symbolicFieldsNeedingResolution.isEmpty()) {
- // If a previous request initiated a resolution request, join that resolutions future instead.
- // If not, initiate a new resolution request.
- final CompletableFuture<Void> resolutionComplete =
- CompletableFuture.allOf(symbolicFieldsNeedingResolution.stream().map(symbolicAdsField -> {
- if (pendingResolutionRequests.containsKey(symbolicAdsField)) {
- return pendingResolutionRequests.get(symbolicAdsField);
- } else {
- // Initiate a new resolution-request and add that to the pending resolution requests.
- CompletableFuture<DirectAdsField> internalResolutionFuture =
- resolveSymbolicAddress(symbolicAdsField);
- // Create a second future which will be completed as soon as the resolution result has
- // been added to the map.
- CompletableFuture<DirectAdsField> resolutionFuture = new CompletableFuture<>();
- // Make sure the resolved address is added to the mapping.
- internalResolutionFuture.thenAccept(directAdsField -> {
- symbolicFieldMapping.put(symbolicAdsField, directAdsField);
- // Now we can tell the other waiting processes about the result.
- resolutionFuture.complete(directAdsField);
- });
- return resolutionFuture;
+ if (!symbolicFieldsNeedingResolution.isEmpty()) {
+ // Get a list of symbolic addresses for which no resolution request has been sent yet
+ // (A parallel request initiated a bit earlier might have already initiated a resolution
+ // which has not yet been completed)
+ final List<SymbolicAdsField> requiredResolutionFields =
+ symbolicFieldsNeedingResolution.stream().filter(symbolicAdsField ->
+ !pendingResolutionRequests.containsKey(symbolicAdsField)).collect(Collectors.toList());
+ // If there are fields for which no resolution request has been sent yet,
+ // send a request.
+ if (!requiredResolutionFields.isEmpty()) {
+ CompletableFuture<Void> resolutionFuture;
+ // Create a future which will be completed as soon as the
+ // resolution result has been added to the map.
+ if (requiredResolutionFields.size() == 1) {
+ SymbolicAdsField symbolicAdsField = requiredResolutionFields.get(0);
+ resolutionFuture = resolveSymbolicAddress(requiredResolutionFields.get(0));
+ pendingResolutionRequests.put(symbolicAdsField, resolutionFuture);
+ } else {
+ resolutionFuture = resolveSymbolicAddresses(requiredResolutionFields);
+ for (SymbolicAdsField symbolicAdsField : requiredResolutionFields) {
+ pendingResolutionRequests.put(symbolicAdsField, resolutionFuture);
}
- }).toArray(CompletableFuture[]::new));
- // Wait for the resolution to finish.
+ }
+ }
+
+ // Create a global future which is completed as soon as all sub-futures for this request are completed.
+ final CompletableFuture<Void> resolutionComplete =
+ CompletableFuture.allOf(symbolicFieldsNeedingResolution.stream()
+ .map(symbolicAdsField -> pendingResolutionRequests.get(symbolicAdsField))
+ .toArray(CompletableFuture[]::new));
+
+ // BLOCKING: Wait for the resolution to finish.
+ // TODO: Make this asynchronous ...
try {
resolutionComplete.get(configuration.getTimeoutSymbolicAddressResolution(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
@@ -238,7 +326,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
// So here all fields should be resolved so we can continue normally.
return fields.stream().map(plcField -> {
- if(plcField instanceof SymbolicAdsField) {
+ if (plcField instanceof SymbolicAdsField) {
return symbolicFieldMapping.get(plcField);
} else {
return (DirectAdsField) plcField;
@@ -246,8 +334,114 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsPacket> implements Ha
}).collect(Collectors.toList());
}
- protected CompletableFuture<DirectAdsField> resolveSymbolicAddress(SymbolicAdsField symbolicAdsField) {
- return null;
+ protected CompletableFuture<Void> resolveSymbolicAddress(SymbolicAdsField symbolicAdsField) {
+ CompletableFuture<Void> future = new CompletableFuture<>();
+
+ // TODO: Instead of using 4 we need the size of the expected response
+ AdsData adsData = new AdsReadWriteRequest(ReservedIndexGroups.ADSIGRP_SYM_HNDBYNAME.getValue(), 0, 4, null,
+ getNullByteTerminatedArray(symbolicAdsField.getSymbolicField()));
+ AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
+ configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
+ CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, invokeIdGenerator.getAndIncrement(), adsData);
+
+ // Start a new request-transaction (Is ended in the response-handler)
+ RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+ transaction.submit(() -> context.sendRequest(amsPacket)
+ .expectResponse(AmsPacket.class, Duration.ofMillis(configuration.getTimeoutRequest()))
+ .onTimeout(future::completeExceptionally)
+ .onError((p, e) -> future.completeExceptionally(e))
+ .check(responseAmsPacket -> responseAmsPacket.getInvokeId() == amsPacket.getInvokeId())
+ .unwrap(AmsPacket::getData)
+ .check(adsDataResponse -> adsDataResponse instanceof AdsReadWriteResponse)
+ .unwrap(adsDataResponse -> (AdsReadWriteResponse) adsDataResponse)
+ .handle(responseAdsData -> {
+ ReadBuffer readBuffer = new ReadBuffer(responseAdsData.getData());
+ try {
+ // This should be 0 in the success case.
+ long returnCode = readBuffer.readLong(32);
+ // This is always 4
+ long itemLength = readBuffer.readLong(32);
+ // Get the handle from the response.
+ long handle = readBuffer.readLong(32);
+ if (returnCode == 0) {
+ DirectAdsField directAdsField = new DirectAdsField(ReservedIndexGroups.ADSIGRP_SYM_VALBYHND.getValue(),
+ handle, symbolicAdsField.getAdsDataType(), symbolicAdsField.getNumberOfElements());
+ symbolicFieldMapping.put(symbolicAdsField, directAdsField);
+ future.complete(null);
+ } else {
+ // TODO: Handle the case of unsuccessful resolution ..
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }));
+ return future;
+ }
+
+ protected CompletableFuture<Void> resolveSymbolicAddresses(List<SymbolicAdsField> symbolicAdsFields) {
+ CompletableFuture<Void> future = new CompletableFuture<>();
+
+ // TODO: Instead of using 4 we need the size of the expected response
+ AdsData adsData = new AdsReadWriteRequest(ReservedIndexGroups.ADSIGRP_MULTIPLE_GET_HANDLE.getValue(),
+ symbolicAdsFields.size(), 4, symbolicAdsFields.stream().map(symbolicAdsField ->
+ new AdsReadWriteRequest(ReservedIndexGroups.ADSIGRP_SYM_HNDBYNAME.getValue(), 0, 4, null,
+ getNullByteTerminatedArray(symbolicAdsField.getSymbolicField()))).toArray(AdsReadWriteRequest[]::new), null);
+ AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
+ configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
+ CommandId.ADS_READ_WRITE, DEFAULT_COMMAND_STATE, 0, invokeIdGenerator.getAndIncrement(), adsData);
+
+ // Start a new request-transaction (Is ended in the response-handler)
+ RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+ transaction.submit(() -> context.sendRequest(amsPacket)
+ .expectResponse(AmsPacket.class, Duration.ofMillis(configuration.getTimeoutRequest()))
+ .onTimeout(future::completeExceptionally)
+ .onError((p, e) -> future.completeExceptionally(e))
+ .check(responseAmsPacket -> responseAmsPacket.getInvokeId() == amsPacket.getInvokeId())
+ .unwrap(AmsPacket::getData)
+ .check(adsDataResponse -> adsDataResponse instanceof AdsReadWriteResponse)
+ .unwrap(adsDataResponse -> (AdsReadWriteResponse) adsDataResponse)
+ .handle(responseAdsData -> {
+ ReadBuffer readBuffer = new ReadBuffer(responseAdsData.getData());
+ Map<SymbolicAdsField, Long> returnCodes = new HashMap<>();
+ symbolicAdsFields.forEach(symbolicAdsField -> {
+ try {
+ // This should be 0 in the success case.
+ long returnCode = readBuffer.readLong(32);
+ // This is always 4
+ long itemLength = readBuffer.readLong(32);
+
+ returnCodes.put(symbolicAdsField, returnCode);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ });
+ symbolicAdsFields.forEach(symbolicAdsField -> {
+ try {
+ if (returnCodes.get(symbolicAdsField) == 0) {
+ // Read the handle.
+ long handle = readBuffer.readLong(32);
+
+ DirectAdsField directAdsField = new DirectAdsField(
+ ReservedIndexGroups.ADSIGRP_SYM_VALBYHND.getValue(), handle,
+ symbolicAdsField.getAdsDataType(), symbolicAdsField.getNumberOfElements());
+ symbolicFieldMapping.put(symbolicAdsField, directAdsField);
+ } else {
+ // TODO: Handle the case of unsuccessful resolution ..
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ });
+ future.complete(null);
+ }));
+ return future;
+ }
+
+ protected byte[] getNullByteTerminatedArray(String value) {
+ byte[] valueBytes = value.getBytes();
+ byte[] nullTerminatedBytes = new byte[valueBytes.length + 1];
+ System.arraycopy(valueBytes, 0, nullTerminatedBytes, 0, valueBytes.length);
+ return nullTerminatedBytes;
}
}
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/package-info.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/package-info.java
deleted file mode 100644
index 123c1c7..0000000
--- a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/protocol/util/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- 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.
- */
-/**
- * This package contains utils regarding endianess and crc digest.
- */
-package org.apache.plc4x.java.amsads.protocol.util;
\ No newline at end of file
diff --git a/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/utils/StaticHelper.java b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/utils/StaticHelper.java
new file mode 100644
index 0000000..f218b14
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/main/java/org/apache/plc4x/java/amsads/utils/StaticHelper.java
@@ -0,0 +1,37 @@
+/*
+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.utils;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+public class StaticHelper {
+
+ public static String parseAmsString(ReadBuffer io, Object encoding) {
+ return "";
+ }
+
+ public static void serializeAmsString(WriteBuffer io, PlcValue value, Object encoding) {
+ // TODO: Need to implement the serialization or we can't write strings
+ throw new PlcRuntimeException("Not implemented yet");
+ }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver b/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
index f59c2cd..332bf55 100644
--- a/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
+++ b/sandbox/test-java-amsads-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
@@ -16,23 +16,4 @@
# 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/protocol/amsads/AdsDriverIT.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AdsDriverIT.java
new file mode 100644
index 0000000..5ffcada
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AdsDriverIT.java
@@ -0,0 +1,29 @@
+/*
+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.test.driver.DriverTestsuiteRunner;
+
+public class AdsDriverIT extends DriverTestsuiteRunner {
+
+ public AdsDriverIT() {
+ super("/testsuite/AdsDriverIT.xml");
+ }
+
+}
diff --git a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AmsAdsSerializerParserTest.java b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AdsSerializerParserTest.java
similarity index 88%
rename from sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AmsAdsSerializerParserTest.java
rename to sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AdsSerializerParserTest.java
index 360d92f..fbb55ca 100644
--- a/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AmsAdsSerializerParserTest.java
+++ b/sandbox/test-java-amsads-driver/src/test/java/org/apache/plc4x/protocol/amsads/AdsSerializerParserTest.java
@@ -22,9 +22,9 @@ package org.apache.plc4x.protocol.amsads;
import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
-public class AmsAdsSerializerParserTest extends ParserSerializerTestsuiteRunner {
+public class AdsSerializerParserTest extends ParserSerializerTestsuiteRunner {
- public AmsAdsSerializerParserTest() {
+ public AdsSerializerParserTest() {
super("/testsuite/AdsParserSerializerTest.xml");
}
diff --git a/sandbox/test-java-amsads-driver/src/test/resources/testsuite/AdsDriverIT.xml b/sandbox/test-java-amsads-driver/src/test/resources/testsuite/AdsDriverIT.xml
new file mode 100644
index 0000000..2f21aee
--- /dev/null
+++ b/sandbox/test-java-amsads-driver/src/test/resources/testsuite/AdsDriverIT.xml
@@ -0,0 +1,463 @@
+<?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:driver-testsuite xmlns:test="https://plc4x.apache.org/schemas/driver-testsuite.xsd"
+ bigEndian="false">
+
+ <name>Beckhoff ADS/AMS</name>
+
+ <driver-name>ads</driver-name>
+ <driver-parameters>
+ <parameter>
+ <name>sourceAmsNetId</name>
+ <value>192.168.23.200.1.1</value>
+ </parameter>
+ <parameter>
+ <name>sourceAmsPort</name>
+ <value>48898</value>
+ </parameter>
+ <parameter>
+ <name>targetAmsNetId</name>
+ <value>192.168.23.20.1.1</value>
+ </parameter>
+ <parameter>
+ <name>targetAmsPort</name>
+ <value>48898</value>
+ </parameter>
+ </driver-parameters>
+
+ <testcase>
+ <name>Single element direct read request</name>
+ <steps>
+ <api-request name="Receive Read Request from application">
+ <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
+ <fields>
+ <field className="org.apache.plc4x.test.driver.model.api.TestField">
+ <name>hurz</name>
+ <address>00004040/00000008:BOOL</address>
+ </field>
+ </fields>
+ </TestReadRequest>
+ </api-request>
+ <outgoing-plc-message name="Send Ads Read Request">
+ <!-- TODO: Should be AmsTCPPacket -->
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>false</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>1</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadRequest">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <length>1</length>
+ </data>
+ </AmsPacket>
+ </outgoing-plc-message>
+ <incoming-plc-message name="Receive Ads Read Response">
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>true</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>1</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadResponse">
+ <result>0</result>
+ <data>AQ==</data>
+ </data>
+ </AmsPacket>
+ </incoming-plc-message>
+ <api-response name="Report Read Response to application">
+ <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
+ <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
+ <hurz className="org.apache.plc4x.java.amsads.field.DirectAdsField">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <adsDataType>BOOL</adsDataType>
+ <numberOfElements>1</numberOfElements>
+ <defaultJavaType>java.lang.Object</defaultJavaType>
+ </hurz>
+ </request>
+ <hurz>
+ <code>OK</code>
+ <value className="org.apache.plc4x.java.api.value.PlcBoolean">
+ <object>true</object>
+ </value>
+ </hurz>
+ </DefaultPlcReadResponse>
+ </api-response>
+ <delay>1000</delay>
+ </steps>
+ </testcase>
+
+ <testcase>
+ <name>Multi element direct read request</name>
+ <steps>
+ <api-request name="Receive Read Request from application">
+ <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
+ <fields>
+ <field className="org.apache.plc4x.test.driver.model.api.TestField">
+ <name>hurz1</name>
+ <address>00004040/00000008:BOOL</address>
+ </field>
+ <field className="org.apache.plc4x.test.driver.model.api.TestField">
+ <name>hurz2</name>
+ <address>00004040/00000012:BOOL</address>
+ </field>
+ </fields>
+ </TestReadRequest>
+ </api-request>
+ <outgoing-plc-message name="Send Ads Read Request">
+ <!-- TODO: Should be AmsTCPPacket -->
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ_WRITE</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>false</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>2</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>61568</indexGroup>
+ <indexOffset>2</indexOffset>
+ <readLength>0</readLength>
+ <items>
+ <items className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <readLength>1</readLength>
+ <items/>
+ <data></data>
+ </items>
+ <items className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>12</indexOffset>
+ <readLength>1</readLength>
+ <items/>
+ <data></data>
+ </items>
+ </items>
+ <data></data>
+ </data>
+ </AmsPacket>
+ </outgoing-plc-message>
+ <incoming-plc-message name="Receive Ads Read Response">
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ_WRITE</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>true</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>2</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteResponse">
+ <result>0</result>
+ <data>AAAAAAAAAAABAQ==</data>
+ </data>
+ </AmsPacket>
+ </incoming-plc-message>
+ <api-response name="Report Read Response to application">
+ <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
+ <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
+ <hurz1 className="org.apache.plc4x.java.amsads.field.DirectAdsField">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <adsDataType>BOOL</adsDataType>
+ <numberOfElements>1</numberOfElements>
+ <defaultJavaType>java.lang.Object</defaultJavaType>
+ </hurz1>
+ <hurz2 className="org.apache.plc4x.java.amsads.field.DirectAdsField">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>12</indexOffset>
+ <adsDataType>BOOL</adsDataType>
+ <numberOfElements>1</numberOfElements>
+ <defaultJavaType>java.lang.Object</defaultJavaType>
+ </hurz2>
+ </request>
+ <hurz1>
+ <code>OK</code>
+ <value className="org.apache.plc4x.java.api.value.PlcBoolean">
+ <object>true</object>
+ </value>
+ </hurz1>
+ <hurz2>
+ <code>OK</code>
+ <value className="org.apache.plc4x.java.api.value.PlcBoolean">
+ <object>true</object>
+ </value>
+ </hurz2>
+ </DefaultPlcReadResponse>
+ </api-response>
+ <delay>1000</delay>
+ </steps>
+ </testcase>
+
+ <!--testcase>
+ <name>Single element symbolic read request</name>
+ <steps>
+ <api-request name="Receive Read Request from application">
+ <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
+ <fields>
+ <field className="org.apache.plc4x.test.driver.model.api.TestField">
+ <name>hurz1</name>
+ <address>main.f_trigDateiGelesen.M:BOOL</address>
+ </field>
+ </fields>
+ </TestReadRequest>
+ </api-request>
+ <outgoing-plc-message name="Send Ads Read Request">
+ <!- TODO: Should be AmsTCPPacket ->
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ_WRITE</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>false</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>2</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>61568</indexGroup>
+ <indexOffset>2</indexOffset>
+ <readLength>0</readLength>
+ <items>
+ <items className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <readLength>1</readLength>
+ <items/>
+ <data></data>
+ </items>
+ <items className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteRequest">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>12</indexOffset>
+ <readLength>1</readLength>
+ <items/>
+ <data></data>
+ </items>
+ </items>
+ <data></data>
+ </data>
+ </AmsPacket>
+ </outgoing-plc-message>
+ <incoming-plc-message name="Receive Ads Read Response">
+ <AmsPacket className="org.apache.plc4x.java.amsads.readwrite.AmsPacket">
+ <targetAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>200</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </targetAmsNetId>
+ <targetAmsPort>48898</targetAmsPort>
+ <sourceAmsNetId className="org.apache.plc4x.java.amsads.readwrite.AmsNetId">
+ <octet1>192</octet1>
+ <octet2>168</octet2>
+ <octet3>23</octet3>
+ <octet4>20</octet4>
+ <octet5>1</octet5>
+ <octet6>1</octet6>
+ </sourceAmsNetId>
+ <sourceAmsPort>48898</sourceAmsPort>
+ <commandId>ADS_READ_WRITE</commandId>
+ <state className="org.apache.plc4x.java.amsads.readwrite.State">
+ <initCommand>false</initCommand>
+ <updCommand>false</updCommand>
+ <timestampAdded>false</timestampAdded>
+ <highPriorityCommand>false</highPriorityCommand>
+ <systemCommand>false</systemCommand>
+ <adsCommand>true</adsCommand>
+ <noReturn>false</noReturn>
+ <response>true</response>
+ <broadcast>false</broadcast>
+ </state>
+ <errorCode>0</errorCode>
+ <invokeId>2</invokeId>
+ <data className="org.apache.plc4x.java.amsads.readwrite.AdsReadWriteResponse">
+ <result>0</result>
+ <data>AAAAAAAAAAABAQ==</data>
+ </data>
+ </AmsPacket>
+ </incoming-plc-message>
+ <api-response name="Report Read Response to application">
+ <DefaultPlcReadResponse className="org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse">
+ <request className="org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest">
+ <hurz1 className="org.apache.plc4x.java.amsads.field.DirectAdsField">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>8</indexOffset>
+ <adsDataType>BOOL</adsDataType>
+ <numberOfElements>1</numberOfElements>
+ <defaultJavaType>java.lang.Object</defaultJavaType>
+ </hurz1>
+ <hurz2 className="org.apache.plc4x.java.amsads.field.DirectAdsField">
+ <indexGroup>4040</indexGroup>
+ <indexOffset>12</indexOffset>
+ <adsDataType>BOOL</adsDataType>
+ <numberOfElements>1</numberOfElements>
+ <defaultJavaType>java.lang.Object</defaultJavaType>
+ </hurz2>
+ </request>
+ <hurz1>
+ <code>OK</code>
+ <value className="org.apache.plc4x.java.api.value.PlcBoolean">
+ <object>true</object>
+ </value>
+ </hurz1>
+ <hurz2>
+ <code>OK</code>
+ <value className="org.apache.plc4x.java.api.value.PlcBoolean">
+ <object>true</object>
+ </value>
+ </hurz2>
+ </DefaultPlcReadResponse>
+ </api-response>
+ <delay>1000</delay>
+ </steps>
+ </testcase-->
+
+</test:driver-testsuite>
\ No newline at end of file