You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2026/08/26 16:29:20 UTC
(plc4x) branch develop updated: fix(codegen/go): honor stringEncoding in data-io, revive the ads testcases
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new 472b29cf7a fix(codegen/go): honor stringEncoding in data-io, revive the ads testcases
472b29cf7a is described below
commit 472b29cf7a0d9f55e3311ae9c8e4452bd5a49651
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Aug 26 18:23:06 2026 +0200
fix(codegen/go): honor stringEncoding in data-io, revive the ads testcases
The Go data-io generator resolved a string field's encoding via
field.getEncoding() only, which never sees the mspec's stringEncoding
attribute, so every generated DataItem read/wrote strings as UTF8 - the
ads WSTRING (UTF16LE per the mspec) decoded the first NUL-terminated
byte ("wolf" -> "w"). The write side additionally emitted a stray ')'
inside the encoding literal ("UTF8)"), which only ever worked because
the byte-based write buffer strips non-alphanumerics from the encoding.
The helper now resolves stringEncoding first, then the global encoding
attribute, then UTF8 (the same precedence getFieldOptions already used),
and the paren typo is gone. plc4go regenerated: the ads/knx/s7 data-io
code now carries the mspec's real encodings (UTF16LE, UTF16BE, ASCII,
ISO-8859-1, WINDOWS1252), replacing the earlier hand-fix, and the
byte-based write buffer treats the single-byte encodings as byte
passthrough instead of silently zero-filling unmatched encodings.
With that in place the four commented-out ads driver testcases are
revived - re-authored against the current drivers' behaviour and green
in BOTH plc4j (strict) and plc4go:
- "Single element direct read request" and "Multi-element direct read
request" (the latter exercising the ADSIGRP_MULTIPLE_READ sum
command): configured AMS ports, hex addresses, invoke-ids continuing
after the 8-request connect handshake
- the two symbolic read testcases now reflect offline resolution against
the symbol table loaded during setup (the old wire-based
handle-resolution exchanges are gone since the rewrite); the
"previously resolved" case reads the same symbol twice and expects
identical resolution with no extra traffic
Driver fixes this surfaced in plc4go/ads:
- the tag handler parsed hex address parts with encoding/hex, rejecting
odd-digit values like 0x8 that plc4j accepts; it now uses ParseUint
- singleRead/multiRead/singleWrite/multiWrite type-asserted tags to
*DirectPlcTag while the tag handler hands out value DirectPlcTags
(every direct-address request failed with "invalid tag item type"),
and never filled the tag's data type table entry; a shared
directTagFor helper now resolves symbolic tags and completes direct
ones in all four paths
Verified: full plc4go test sweep green; plc4j verify (incl. jacoco)
green for spi values/fields/buffers-xml, test-utils, and the ads, s7,
eip, slmp, modbus, canopen and iec-60870 drivers. All 6 ads testcases
active - none commented out anymore.
---
.../language/go/GoLanguageTemplateHelper.java | 57 +-
.../testing/protocols/ads/DriverTestsuite.xml | 658 ++++++---------------
plc4go/internal/ads/Connection.go | 35 ++
plc4go/internal/ads/Reader.go | 58 +-
plc4go/internal/ads/TagHandler.go | 50 +-
plc4go/internal/ads/Writer.go | 50 +-
plc4go/protocols/ads/readwrite/model/DataItem.go | 8 +-
.../knxnetip/readwrite/model/KnxDatapoint.go | 16 +-
.../protocols/modbus/readwrite/model/DataItem.go | 12 +-
.../protocols/opcua/readwrite/model/ChunkType.go | 2 +-
.../protocols/opcua/readwrite/model/MessageType.go | 2 +-
.../opcua/readwrite/model/OpcuaDataType.go | 2 +-
.../opcua/readwrite/model/OpcuaIdentifierType.go | 2 +-
plc4go/protocols/s7/readwrite/model/DataItem.go | 4 +-
.../simulated/readwrite/model/DataItem.go | 12 +-
plc4go/spi/utils/WriteBufferByteBased.go | 5 +-
.../resources/protocols/ads/DriverTestsuite.xml | 658 ++++++---------------
17 files changed, 456 insertions(+), 1175 deletions(-)
diff --git a/code-generation/language/go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java b/code-generation/language/go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
index ef89ca7c5c..29d9bc0f92 100644
--- a/code-generation/language/go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
+++ b/code-generation/language/go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
@@ -496,27 +496,13 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
}
return "/*TODO: migrate me*/" + "readBuffer.ReadBigFloat(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + ")";
case STRING: {
- String encoding = "UTF8";
- if (field != null) {
- final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral(encoding));
- encoding = encodingTerm.asLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a literal"))
- .asStringLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
- }
+ String encoding = getStringEncoding(field);
String length = Integer.toString(simpleTypeReference.getSizeInBits());
return "/*TODO: migrate me*/" + "readBuffer.ReadString(\"" + logicalName + "\", uint32(" + length + "), utils.WithEncoding(\"" + encoding + "\"))";
}
case VSTRING: {
- String encoding = "UTF8";
+ String encoding = getStringEncoding(field);
VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
- if (field != null) {
- final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral(encoding));
- encoding = encodingTerm.asLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a literal"))
- .asStringLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
- }
String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, null, false, false);
if (vstringTypeReference.getLengthExpression().isTernaryTerm()) {
lengthExpression = "(" + lengthExpression + ").(uint32)";
@@ -780,27 +766,13 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
return "/*TODO: migrate me*/" + "writeBuffer.WriteBigFloat(\"" + logicalName + "\", " + floatTypeReference.getSizeInBits() + ", " + fieldName + writerArgsString + ")";
case STRING: {
StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
- String encoding = "UTF8";
- if (field != null) {
- final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral(encoding));
- encoding = encodingTerm.asLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a literal"))
- .asStringLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
- }
+ String encoding = getStringEncoding(field);
String length = Integer.toString(simpleTypeReference.getSizeInBits());
- return "/*TODO: migrate me*/" + "writeBuffer.WriteString(\"" + logicalName + "\", uint32(" + length + "), " + fieldName + writerArgsString + ", utils.WithEncoding(\"" + encoding + ")\"))";
+ return "/*TODO: migrate me*/" + "writeBuffer.WriteString(\"" + logicalName + "\", uint32(" + length + "), " + fieldName + writerArgsString + ", utils.WithEncoding(\"" + encoding + "\"))";
}
case VSTRING: {
VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
- String encoding = "UTF8";
- if (field != null) {
- final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral(encoding));
- encoding = encodingTerm.asLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a literal"))
- .asStringLiteral()
- .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
- }
+ String encoding = getStringEncoding(field);
String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, Collections.singletonList(new DefaultArgument("stringLength", new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.INT, 32))), true, false);
if (vstringTypeReference.getLengthExpression().isTernaryTerm()) {
lengthExpression = "(" + lengthExpression + ").(uint32)";
@@ -808,7 +780,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
lengthExpression = "uint32(" + lengthExpression + ")";
}
String length = Integer.toString(simpleTypeReference.getSizeInBits());
- return "/*TODO: migrate me*/" + "writeBuffer.WriteString(\"" + logicalName + "\", " + lengthExpression + ", " + fieldName + writerArgsString + ", utils.WithEncoding(\"" + encoding + ")\"))";
+ return "/*TODO: migrate me*/" + "writeBuffer.WriteString(\"" + logicalName + "\", " + lengthExpression + ", " + fieldName + writerArgsString + ", utils.WithEncoding(\"" + encoding + "\"))";
}
case DATE:
case TIME:
@@ -1973,6 +1945,23 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
return "";
}
+ /**
+ * Resolves the string encoding of a field: the stringEncoding attribute wins, then a
+ * global encoding attribute, then UTF8 (matching getFieldOptions' precedence).
+ */
+ private String getStringEncoding(TypedField field) {
+ if (field == null) {
+ return "UTF8";
+ }
+ final Term encodingTerm = field.getAttribute("stringEncoding")
+ .or(field::getEncoding)
+ .orElse(new DefaultStringLiteral("UTF8"));
+ return encodingTerm.asLiteral()
+ .orElseThrow(() -> new FreemarkerException("Encoding must be a literal"))
+ .asStringLiteral()
+ .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
+ }
+
public String getFieldOptions(TypedField field, List<Argument> parserArguments) {
StringBuilder sb = new StringBuilder();
field.getAttribute("stringEncoding").ifPresentOrElse(term -> {
diff --git a/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml b/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
index 021ce08bfc..b708cff6d5 100644
--- a/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
+++ b/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
@@ -1491,7 +1491,7 @@
</steps>
</testcase>
- <!--testcase>
+ <testcase>
<name>Single element direct read request</name>
<description>
When doing a simple read request with only a single direct address, the
@@ -1501,10 +1501,10 @@
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz</name>
- <address>00004040/00000008:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz</name>
+ <address>0x4040/0x8:BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
@@ -1524,18 +1524,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1553,11 +1553,11 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">8</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
@@ -1574,12 +1574,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -1590,7 +1590,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1608,38 +1608,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">1</length>
- <data dataType="byte" bitLength="8">0x01</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">8</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz>
<PlcResponseItem>
@@ -1652,35 +1634,34 @@
</values>
</PlcReadResponse>
</api-response>
- <delay>1000</delay>
</steps>
</testcase>
<testcase>
<name>Multi-element direct read request</name>
<description>
- When doing a simple read request with only direct addresses, but multiple
- ones, the unofficial multi-read method should be used to read all in one go.
+ When doing a read request with multiple direct addresses, the request is packed
+ into a single ADS sum command and the merged response is split up again.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>00004040/00000008:BOOL</address>
- </tag>
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz2</name>
- <address>00004040/00000012:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>0x4040/0x8:BOOL</address>
+ </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz2</name>
+ <address>0x4040/0xC:BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Ads Read Request">
+ <outgoing-plc-message name="Send Ads Sum Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
+ <length dataType="uint" bitLength="32">72</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -1693,20 +1674,20 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
+ <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
</commandId>
<initCommand dataType="bit" bitLength="1">false</initCommand>
<updCommand dataType="bit" bitLength="1">false</updCommand>
@@ -1718,22 +1699,39 @@
<response dataType="bit" bitLength="1">false</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
+ <length dataType="uint" bitLength="32">40</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
- </AdsReadRequest>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadWriteRequest>
+ <indexGroup dataType="uint" bitLength="32">61568</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">2</indexOffset>
+ <readLength dataType="uint" bitLength="32">10</readLength>
+ <writeLength dataType="uint" bitLength="32">24</writeLength>
+ <items isList="true">
+ <AdsMultiRequestItem>
+ <AdsMultiRequestItemRead>
+ <itemIndexGroup dataType="uint" bitLength="32">16448</itemIndexGroup>
+ <itemIndexOffset dataType="uint" bitLength="32">8</itemIndexOffset>
+ <itemReadLength dataType="uint" bitLength="32">1</itemReadLength>
+ </AdsMultiRequestItemRead>
+ </AdsMultiRequestItem>
+ <AdsMultiRequestItem>
+ <AdsMultiRequestItemRead>
+ <itemIndexGroup dataType="uint" bitLength="32">16448</itemIndexGroup>
+ <itemIndexOffset dataType="uint" bitLength="32">12</itemIndexOffset>
+ <itemReadLength dataType="uint" bitLength="32">1</itemReadLength>
+ </AdsMultiRequestItemRead>
+ </AdsMultiRequestItem>
+ </items>
+ <data dataType="byte" bitLength="0">0x</data>
+ </AdsReadWriteRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
-
</outgoing-plc-message>
- <incoming-plc-message name="Receive Ads Read Response">
+ <incoming-plc-message name="Receive Ads Sum Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">50</length>
@@ -1744,12 +1742,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -1760,7 +1758,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
</commandId>
@@ -1778,46 +1776,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadWriteResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">10</length>
+ <data dataType="byte" bitLength="80">0x00000000000000000101</data>
+ </AdsReadWriteResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">8</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz1>
- <hurz2>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">12</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz2>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
@@ -1838,29 +1810,28 @@
</values>
</PlcReadResponse>
</api-response>
- <delay>1000</delay>
</steps>
</testcase>
<testcase>
<name>Single element symbolic read request</name>
<description>
- When doing a simple read request with only a single symbolic address, which has not
- been resolved previously, first a resolution request has to be issued and the data
- from the response should be used in a second request to actually read the data.
+ A read request with a symbolic address is resolved offline against the symbol- and
+ data-type-tables loaded during connection setup, so only the direct read of the
+ resolved address goes on the wire.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Resolve Symbolic Address Request">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -1876,18 +1847,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1905,140 +1876,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Resolve Symbolic Address Response">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">true</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">4</length>
- <data dataType="byte" bitLength="32">0x0100801b</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </incoming-plc-message>
- <outgoing-plc-message name="Send Ads Read Request">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">false</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </outgoing-plc-message>
<incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2046,12 +1897,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2062,7 +1913,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2076,47 +1927,30 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
@@ -2129,22 +1963,21 @@
<testcase>
<name>Single element symbolic read request (Address previously resolved)</name>
<description>
- When doing a simple read request with only a single symbolic address, which has
- been resolved previously, the data from the previous request should be used directly
- without re-resolving it.
+ Reading the same symbolic address twice resolves to the same direct address both
+ times without any additional resolution traffic on the wire.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Resolve Symbolic Address Request">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -2160,18 +1993,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2189,141 +2022,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Resolve Symbolic Address Response">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">true</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">4</length>
- <data dataType="byte" bitLength="32">0x0100801b</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </incoming-plc-message>
- <outgoing-plc-message name="Send Ads Read Request">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">false</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
-
- </outgoing-plc-message>
<incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2331,12 +2043,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2347,7 +2059,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2361,66 +2073,47 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
-
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
</values>
</PlcReadResponse>
</api-response>
- <delay>500</delay>
- <api-request name="Receive a second Read Request for the same resource from application">
+ <api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Ads Read Request directly using the preciously resolved address">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -2436,18 +2129,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2465,24 +2158,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">3</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">10</invokeId>
+ <AdsReadRequest>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
+ </AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Ads Read Response again">
+ <incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2490,12 +2179,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2506,7 +2195,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2520,47 +2209,30 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">3</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">10</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
- <api-response name="Report Read Response to application again">
+ <api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
@@ -2568,6 +2240,6 @@
</PlcReadResponse>
</api-response>
</steps>
- </testcase-->
+ </testcase>
</test:driver-testsuite>
diff --git a/plc4go/internal/ads/Connection.go b/plc4go/internal/ads/Connection.go
index e1eff2a8fd..9bf6c9e79a 100644
--- a/plc4go/internal/ads/Connection.go
+++ b/plc4go/internal/ads/Connection.go
@@ -352,6 +352,41 @@ func (m *Connection) readSymbolTable(ctx context.Context, symbolTableSize uint32
return symbols, nil
}
+// directTagFor returns a request tag as a fully usable direct tag: symbolic tags are
+// resolved against the tables loaded during connection setup, and direct tags created
+// straight from an address string get their data type table entry filled in.
+func (m *Connection) directTagFor(ctx context.Context, tag apiModel.PlcTag) (*model.DirectPlcTag, error) {
+ var directTag model.DirectPlcTag
+ switch typedTag := tag.(type) {
+ case model.SymbolicPlcTag:
+ resolvedTag, err := m.resolveSymbolicTag(ctx, typedTag)
+ if err != nil {
+ return nil, errors.Wrap(err, "error resolving symbolic tag")
+ }
+ return resolvedTag, nil
+ case *model.SymbolicPlcTag:
+ resolvedTag, err := m.resolveSymbolicTag(ctx, *typedTag)
+ if err != nil {
+ return nil, errors.Wrap(err, "error resolving symbolic tag")
+ }
+ return resolvedTag, nil
+ case model.DirectPlcTag:
+ directTag = typedTag
+ case *model.DirectPlcTag:
+ directTag = *typedTag
+ default:
+ return nil, errors.Errorf("invalid tag type %T", tag)
+ }
+ if directTag.DataType == nil {
+ dataType, ok := m.driverContext.dataTypeTable[directTag.ValueType.String()]
+ if !ok {
+ return nil, errors.Errorf("no entry for data type %s in the data type table", directTag.ValueType)
+ }
+ directTag.DataType = dataType
+ }
+ return &directTag, nil
+}
+
func (m *Connection) resolveSymbolicTag(ctx context.Context, symbolicTag model.SymbolicPlcTag) (*model.DirectPlcTag, error) {
// Find the initial datatype, based on the first to segments.
symbolicAddress := symbolicTag.SymbolicAddress
diff --git a/plc4go/internal/ads/Reader.go b/plc4go/internal/ads/Reader.go
index 872c64c6bd..858764f455 100644
--- a/plc4go/internal/ads/Reader.go
+++ b/plc4go/internal/ads/Reader.go
@@ -68,28 +68,9 @@ func (m *Connection) singleRead(ctx context.Context, readRequest apiModel.PlcRea
// Here we can be sure that we're only handling a single request.
tagName := readRequest.GetTagNames()[0]
tag := readRequest.GetTag(tagName)
- if model.NeedsResolving(tag) {
- adsField, err := model.CastToSymbolicPlcTagFromPlcTag(tag)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(readRequest, nil, errors.Wrap(err, "invalid tag item type")))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- // Replace the symbolic tag with a direct one
- tag, err = m.resolveSymbolicTag(ctx, adsField)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(
- readRequest,
- nil,
- errors.Wrap(err, "invalid tag item type"),
- ))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- }
- directAdsTag, ok := tag.(*model.DirectPlcTag)
- if !ok {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(readRequest, nil, errors.New("invalid tag item type")))
+ directAdsTag, err := m.directTagFor(ctx, tag)
+ if err != nil {
+ utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(readRequest, nil, errors.Wrap(err, "invalid tag item type")))
m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
return
}
@@ -146,36 +127,9 @@ func (m *Connection) multiRead(ctx context.Context, readRequest apiModel.PlcRead
requestItems := make([]driverModel.AdsMultiRequestItem, 0)
for _, tagName := range readRequest.GetTagNames() {
tag := readRequest.GetTag(tagName)
- if model.NeedsResolving(tag) {
- adsField, err := model.CastToSymbolicPlcTagFromPlcTag(tag)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(
- readRequest,
- nil,
- errors.Wrap(err, "invalid tag item type"),
- ))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- // Replace the symbolic tag with a direct one
- tag, err = m.resolveSymbolicTag(ctx, adsField)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(
- readRequest,
- nil,
- errors.Wrap(err, "invalid tag item type"),
- ))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- }
- directAdsTag, ok := tag.(*model.DirectPlcTag)
- if !ok {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(
- readRequest,
- nil,
- errors.New("invalid tag item type"),
- ))
+ directAdsTag, err := m.directTagFor(ctx, tag)
+ if err != nil {
+ utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcReadRequestResult(readRequest, nil, errors.Wrap(err, "invalid tag item type")))
m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
return
}
diff --git a/plc4go/internal/ads/TagHandler.go b/plc4go/internal/ads/TagHandler.go
index 1074dfbb16..8ef482b531 100644
--- a/plc4go/internal/ads/TagHandler.go
+++ b/plc4go/internal/ads/TagHandler.go
@@ -20,8 +20,6 @@
package ads
import (
- "encoding/binary"
- "encoding/hex"
"fmt"
"regexp"
"strconv"
@@ -68,15 +66,13 @@ func (m TagHandler) ParseTag(query string) (apiModel.PlcTag, error) {
if match := utils.GetSubgroupMatches(m.directAdsStringTag, query); match != nil {
var indexGroup uint32
if indexGroupHexString := match["indexGroupHex"]; indexGroupHexString != "" {
- decodeString, err := hex.DecodeString(indexGroupHexString)
+ // ParseUint instead of hex.DecodeString: addresses like 0x8 have an odd
+ // number of digits, which byte-wise decoding rejects.
+ parsed, err := strconv.ParseUint(indexGroupHexString, 16, 32)
if err != nil {
- return nil, errors.Wrap(err, "Error decoding index group")
- }
- // Fill up the array with missing bytes to get an array of size 4 bytes.
- for i := len(decodeString); i < 4; i++ {
- decodeString = append([]byte{0}, decodeString...)
+ return nil, errors.Wrap(err, "Error decoding indexGroup")
}
- indexGroup = binary.BigEndian.Uint32(decodeString)
+ indexGroup = uint32(parsed)
} else {
parsedIndexGroup, err := strconv.ParseUint(match["indexGroup"], 10, 32)
if err != nil {
@@ -86,15 +82,13 @@ func (m TagHandler) ParseTag(query string) (apiModel.PlcTag, error) {
}
var indexOffset uint32
if indexOffsetHexString := match["indexOffsetHex"]; indexOffsetHexString != "" {
- decodeString, err := hex.DecodeString(indexOffsetHexString)
+ // ParseUint instead of hex.DecodeString: addresses like 0x8 have an odd
+ // number of digits, which byte-wise decoding rejects.
+ parsed, err := strconv.ParseUint(indexOffsetHexString, 16, 32)
if err != nil {
- return nil, errors.Wrap(err, "Error decoding index group")
- }
- // Fill up the array with missing bytes to get an array of size 4 bytes.
- for i := len(decodeString); i < 4; i++ {
- decodeString = append([]byte{0}, decodeString...)
+ return nil, errors.Wrap(err, "Error decoding indexOffset")
}
- indexOffset = binary.BigEndian.Uint32(decodeString)
+ indexOffset = uint32(parsed)
} else {
parsedIndexOffset, err := strconv.ParseUint(match["indexOffset"], 10, 32)
if err != nil {
@@ -175,15 +169,13 @@ func (m TagHandler) ParseTag(query string) (apiModel.PlcTag, error) {
} else if match := utils.GetSubgroupMatches(m.directAdsTag, query); match != nil {
var indexGroup uint32
if indexGroupHexString := match["indexGroupHex"]; indexGroupHexString != "" {
- decodeString, err := hex.DecodeString(indexGroupHexString)
+ // ParseUint instead of hex.DecodeString: addresses like 0x8 have an odd
+ // number of digits, which byte-wise decoding rejects.
+ parsed, err := strconv.ParseUint(indexGroupHexString, 16, 32)
if err != nil {
- return nil, errors.Wrap(err, "Error decoding index group")
- }
- // Fill up the array with missing bytes to get an array of size 4 bytes.
- for i := len(decodeString); i < 4; i++ {
- decodeString = append([]byte{0}, decodeString...)
+ return nil, errors.Wrap(err, "Error decoding indexGroup")
}
- indexGroup = binary.BigEndian.Uint32(decodeString)
+ indexGroup = uint32(parsed)
} else {
parsedIndexGroup, err := strconv.ParseUint(match["indexGroup"], 10, 32)
if err != nil {
@@ -193,15 +185,13 @@ func (m TagHandler) ParseTag(query string) (apiModel.PlcTag, error) {
}
var indexOffset uint32
if indexOffsetHexString := match["indexOffsetHex"]; indexOffsetHexString != "" {
- decodeString, err := hex.DecodeString(indexOffsetHexString)
+ // ParseUint instead of hex.DecodeString: addresses like 0x8 have an odd
+ // number of digits, which byte-wise decoding rejects.
+ parsed, err := strconv.ParseUint(indexOffsetHexString, 16, 32)
if err != nil {
- return nil, errors.Wrap(err, "Error decoding index group")
- }
- // Fill up the array with missing bytes to get an array of size 4 bytes.
- for i := len(decodeString); i < 4; i++ {
- decodeString = append([]byte{0}, decodeString...)
+ return nil, errors.Wrap(err, "Error decoding indexOffset")
}
- indexOffset = binary.BigEndian.Uint32(decodeString)
+ indexOffset = uint32(parsed)
} else {
parsedIndexOffset, err := strconv.ParseUint(match["indexOffset"], 10, 32)
if err != nil {
diff --git a/plc4go/internal/ads/Writer.go b/plc4go/internal/ads/Writer.go
index 0bc7b0873f..e9966ac4b1 100644
--- a/plc4go/internal/ads/Writer.go
+++ b/plc4go/internal/ads/Writer.go
@@ -67,28 +67,9 @@ func (m *Connection) singleWrite(ctx context.Context, writeRequest apiModel.PlcW
// Here we can be sure that we're only handling a single request.
tagName := writeRequest.GetTagNames()[0]
tag := writeRequest.GetTag(tagName)
- if model.NeedsResolving(tag) {
- adsField, err := model.CastToSymbolicPlcTagFromPlcTag(tag)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(
- writeRequest,
- nil,
- errors.Wrap(err, "invalid tag item type"),
- ))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- // Replace the symbolic tag with a direct one
- tag, err = m.resolveSymbolicTag(ctx, adsField)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "invalid tag item type")))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- }
- directAdsTag, ok := tag.(*model.DirectPlcTag)
- if !ok {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.New("invalid tag item type")))
+ directAdsTag, err := m.directTagFor(ctx, tag)
+ if err != nil {
+ utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "invalid tag item type")))
m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
return
}
@@ -96,7 +77,7 @@ func (m *Connection) singleWrite(ctx context.Context, writeRequest apiModel.PlcW
// Get the value from the request and serialize it to a byte array
value := writeRequest.GetValue(tagName)
io := utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian))
- err := m.serializePlcValue(directAdsTag.DataType, directAdsTag.GetArrayInfo(), value, io)
+ err = m.serializePlcValue(directAdsTag.DataType, directAdsTag.GetArrayInfo(), value, io)
if err != nil {
utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "error serializing plc value")))
return
@@ -140,24 +121,9 @@ func (m *Connection) multiWrite(ctx context.Context, writeRequest apiModel.PlcWr
io := utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian))
for _, tagName := range writeRequest.GetTagNames() {
tag := writeRequest.GetTag(tagName)
- if model.NeedsResolving(tag) {
- adsField, err := model.CastToSymbolicPlcTagFromPlcTag(tag)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "invalid tag item type")))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- // Replace the symbolic tag with a direct one
- tag, err = m.resolveSymbolicTag(ctx, adsField)
- if err != nil {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "invalid tag item type")))
- m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
- return
- }
- }
- directAdsTag, ok := tag.(*model.DirectPlcTag)
- if !ok {
- utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.New("invalid tag item type")))
+ directAdsTag, err := m.directTagFor(ctx, tag)
+ if err != nil {
+ utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "invalid tag item type")))
m.log.Debug().Type("tag", tag).Msg("Invalid tag item type")
return
}
@@ -165,7 +131,7 @@ func (m *Connection) multiWrite(ctx context.Context, writeRequest apiModel.PlcWr
directAdsTags[tagName] = directAdsTag
// Serialize the plc value
- err := m.serializePlcValue(directAdsTag.DataType, directAdsTag.GetArrayInfo(), writeRequest.GetValue(tagName), io)
+ err = m.serializePlcValue(directAdsTag.DataType, directAdsTag.GetArrayInfo(), writeRequest.GetValue(tagName), io)
if err != nil {
utils.DeliverResult(m.log, result, spiModel.NewDefaultPlcWriteRequestResult(writeRequest, nil, errors.Wrap(err, "error serializing plc value")))
return
diff --git a/plc4go/protocols/ads/readwrite/model/DataItem.go b/plc4go/protocols/ads/readwrite/model/DataItem.go
index 61c16a4666..22f7ab9809 100644
--- a/plc4go/protocols/ads/readwrite/model/DataItem.go
+++ b/plc4go/protocols/ads/readwrite/model/DataItem.go
@@ -184,7 +184,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, p
return values.NewPlcLREAL(value), nil
case plcValueType == api.CHAR: // CHAR
// Simple Field (value)
- value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(8), utils.WithEncoding("UTF8"))
+ value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(8), utils.WithEncoding("WINDOWS1252"))
if _valueErr != nil {
return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
}
@@ -202,7 +202,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, p
return values.NewPlcWCHAR(value), nil
case plcValueType == api.STRING: // STRING
// Simple Field (value)
- value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32((stringLength)*(8)), utils.WithEncoding("UTF8"))
+ value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32((stringLength)*(8)), utils.WithEncoding("WINDOWS1252"))
if _valueErr != nil {
return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
}
@@ -418,7 +418,7 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
}
case plcValueType == api.CHAR: // CHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("WINDOWS1252")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case plcValueType == api.WCHAR: // WCHAR
@@ -428,7 +428,7 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
}
case plcValueType == api.STRING: // STRING
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("WINDOWS1252")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
diff --git a/plc4go/protocols/knxnetip/readwrite/model/KnxDatapoint.go b/plc4go/protocols/knxnetip/readwrite/model/KnxDatapoint.go
index c5a1e72590..325f2bff67 100644
--- a/plc4go/protocols/knxnetip/readwrite/model/KnxDatapoint.go
+++ b/plc4go/protocols/knxnetip/readwrite/model/KnxDatapoint.go
@@ -272,7 +272,7 @@ func KnxDatapointParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffe
}
// Simple Field (value)
- value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF8"))
+ value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF16"))
if _valueErr != nil {
return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
}
@@ -8530,7 +8530,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_WCHAR: // WCHAR
@@ -8540,7 +8540,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_TIME: // TIME
@@ -9140,7 +9140,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("ASCII)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("ASCII")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_DPT_Char_8859_1: // STRING
@@ -9150,7 +9150,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("ISO-8859-1)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("ISO-8859-1")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_DPT_Scaling: // USINT
@@ -10875,7 +10875,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(112), value.GetString(), utils.WithEncoding("ASCII)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(112), value.GetString(), utils.WithEncoding("ASCII")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_DPT_String_8859_1: // STRING
@@ -10885,7 +10885,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(112), value.GetString(), utils.WithEncoding("ISO-8859-1)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(112), value.GetString(), utils.WithEncoding("ISO-8859-1")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_DPT_SceneNumber: // USINT
@@ -13185,7 +13185,7 @@ func KnxDatapointSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils
}
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("ASCII)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("ASCII")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case datapointType == KnxDatapointType_DPT_Tariff_ActiveEnergy: // Struct
diff --git a/plc4go/protocols/modbus/readwrite/model/DataItem.go b/plc4go/protocols/modbus/readwrite/model/DataItem.go
index 34dae55f39..873673c9ef 100644
--- a/plc4go/protocols/modbus/readwrite/model/DataItem.go
+++ b/plc4go/protocols/modbus/readwrite/model/DataItem.go
@@ -187,7 +187,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, d
return values.NewPlcCHAR(value), nil
case dataType == ModbusDataType_WCHAR: // WCHAR
// Simple Field (value)
- value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF8"))
+ value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF16BE"))
if _valueErr != nil {
return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
}
@@ -205,7 +205,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, d
return values.NewPlcSTRING(value), nil
case dataType == ModbusDataType_WSTRING: // WSTRING
// Simple Field (value)
- value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32((stringLength)*(16)), utils.WithEncoding("UTF8"))
+ value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32((stringLength)*(16)), utils.WithEncoding("UTF16BE"))
if _valueErr != nil {
return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
}
@@ -325,22 +325,22 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
}
case dataType == ModbusDataType_CHAR: // CHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == ModbusDataType_WCHAR: // WCHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16BE")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == ModbusDataType_STRING: // STRING
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == ModbusDataType_WSTRING: // WSTRING
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(16)), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(16)), value.GetString(), utils.WithEncoding("UTF16BE")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
default:
diff --git a/plc4go/protocols/opcua/readwrite/model/ChunkType.go b/plc4go/protocols/opcua/readwrite/model/ChunkType.go
index 5d80bb07b5..b22a215173 100644
--- a/plc4go/protocols/opcua/readwrite/model/ChunkType.go
+++ b/plc4go/protocols/opcua/readwrite/model/ChunkType.go
@@ -138,7 +138,7 @@ func (e ChunkType) Serialize() ([]byte, error) {
func (e ChunkType) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
log := zerolog.Ctx(ctx)
_ = log
- return /*TODO: migrate me*/ writeBuffer.WriteString("ChunkType", uint32(8), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8)"))
+ return /*TODO: migrate me*/ writeBuffer.WriteString("ChunkType", uint32(8), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8"))
}
func (e ChunkType) GetValue() string {
diff --git a/plc4go/protocols/opcua/readwrite/model/MessageType.go b/plc4go/protocols/opcua/readwrite/model/MessageType.go
index e614a276d0..5e6cd2492a 100644
--- a/plc4go/protocols/opcua/readwrite/model/MessageType.go
+++ b/plc4go/protocols/opcua/readwrite/model/MessageType.go
@@ -156,7 +156,7 @@ func (e MessageType) Serialize() ([]byte, error) {
func (e MessageType) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
log := zerolog.Ctx(ctx)
_ = log
- return /*TODO: migrate me*/ writeBuffer.WriteString("MessageType", uint32(24), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8)"))
+ return /*TODO: migrate me*/ writeBuffer.WriteString("MessageType", uint32(24), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8"))
}
func (e MessageType) GetValue() string {
diff --git a/plc4go/protocols/opcua/readwrite/model/OpcuaDataType.go b/plc4go/protocols/opcua/readwrite/model/OpcuaDataType.go
index 60c8520879..411708eaa1 100644
--- a/plc4go/protocols/opcua/readwrite/model/OpcuaDataType.go
+++ b/plc4go/protocols/opcua/readwrite/model/OpcuaDataType.go
@@ -378,7 +378,7 @@ func (e OpcuaDataType) Serialize() ([]byte, error) {
func (e OpcuaDataType) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
log := zerolog.Ctx(ctx)
_ = log
- return /*TODO: migrate me*/ writeBuffer.WriteString("OpcuaDataType", uint32(112), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8)"))
+ return /*TODO: migrate me*/ writeBuffer.WriteString("OpcuaDataType", uint32(112), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8"))
}
func (e OpcuaDataType) GetValue() string {
diff --git a/plc4go/protocols/opcua/readwrite/model/OpcuaIdentifierType.go b/plc4go/protocols/opcua/readwrite/model/OpcuaIdentifierType.go
index 59a80f594e..6531cc4657 100644
--- a/plc4go/protocols/opcua/readwrite/model/OpcuaIdentifierType.go
+++ b/plc4go/protocols/opcua/readwrite/model/OpcuaIdentifierType.go
@@ -144,7 +144,7 @@ func (e OpcuaIdentifierType) Serialize() ([]byte, error) {
func (e OpcuaIdentifierType) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
log := zerolog.Ctx(ctx)
_ = log
- return /*TODO: migrate me*/ writeBuffer.WriteString("OpcuaIdentifierType", uint32(8), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8)"))
+ return /*TODO: migrate me*/ writeBuffer.WriteString("OpcuaIdentifierType", uint32(8), string(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()), utils.WithEncoding("UTF8"))
}
func (e OpcuaIdentifierType) GetValue() string {
diff --git a/plc4go/protocols/s7/readwrite/model/DataItem.go b/plc4go/protocols/s7/readwrite/model/DataItem.go
index ac66095b6a..12a67fbdd7 100644
--- a/plc4go/protocols/s7/readwrite/model/DataItem.go
+++ b/plc4go/protocols/s7/readwrite/model/DataItem.go
@@ -518,12 +518,12 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
}
case dataProtocolId == "IEC61131_CHAR": // CHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataProtocolId == "IEC61131_WCHAR": // CHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16BE)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16BE")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataProtocolId == "IEC61131_STRING": // STRING
diff --git a/plc4go/protocols/simulated/readwrite/model/DataItem.go b/plc4go/protocols/simulated/readwrite/model/DataItem.go
index ceb65211a0..296a1cc098 100644
--- a/plc4go/protocols/simulated/readwrite/model/DataItem.go
+++ b/plc4go/protocols/simulated/readwrite/model/DataItem.go
@@ -667,38 +667,38 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
}
case dataType == "CHAR" && numberOfValues == uint16(1): // CHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == "CHAR": // List
// Array Field (value)
for i := uint32(0); i < uint32(m.GetNumberOfValues()); i++ {
- _itemErr := /*TODO: migrate me*/ writeBuffer.WriteString("", uint32(8), value.GetIndex(i).GetString(), utils.WithEncoding("UTF8)"))
+ _itemErr := /*TODO: migrate me*/ writeBuffer.WriteString("", uint32(8), value.GetIndex(i).GetString(), utils.WithEncoding("UTF8"))
if _itemErr != nil {
return errors.Wrap(_itemErr, "Error serializing 'value' field")
}
}
case dataType == "WCHAR" && numberOfValues == uint16(1): // WCHAR
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == "WCHAR": // List
// Array Field (value)
for i := uint32(0); i < uint32(m.GetNumberOfValues()); i++ {
- _itemErr := /*TODO: migrate me*/ writeBuffer.WriteString("", uint32(16), value.GetIndex(i).GetString(), utils.WithEncoding("UTF16)"))
+ _itemErr := /*TODO: migrate me*/ writeBuffer.WriteString("", uint32(16), value.GetIndex(i).GetString(), utils.WithEncoding("UTF16"))
if _itemErr != nil {
return errors.Wrap(_itemErr, "Error serializing 'value' field")
}
}
case dataType == "STRING": // STRING
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(255), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(255), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
case dataType == "WSTRING": // STRING
// Simple Field (value)
- if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(255), value.GetString(), utils.WithEncoding("UTF16)")); _err != nil {
+ if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(255), value.GetString(), utils.WithEncoding("UTF16")); _err != nil {
return errors.Wrap(_err, "Error serializing 'value' field")
}
default:
diff --git a/plc4go/spi/utils/WriteBufferByteBased.go b/plc4go/spi/utils/WriteBufferByteBased.go
index f140ce14ef..65785cc91d 100644
--- a/plc4go/spi/utils/WriteBufferByteBased.go
+++ b/plc4go/spi/utils/WriteBufferByteBased.go
@@ -289,7 +289,10 @@ func (wb *byteWriteBuffer) WriteString(_ string, bitLength uint32, value string,
encoding := nonAlphanumericRegex.ReplaceAllLiteralString(strings.ToUpper(wb.ExtractEncoding(UpcastWriterArgs(writerArgs...)...)), "")
remainingBits := int64(bitLength) // int64 so subtraction doesn't wrap on underflow
switch encoding {
- case "UTF8":
+ case "UTF8", "ASCII", "ISO88591", "WINDOWS1252":
+ // The single-byte encodings write the string's bytes as-is: for the character
+ // ranges the protocols use these are identical, and it avoids silently writing
+ // nothing (the switch's fall-through is plain zero-fill).
for _, b := range []byte(value) {
wb.bits.TryWriteByte(b)
remainingBits -= 8
diff --git a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
index 021ce08bfc..b708cff6d5 100644
--- a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
+++ b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
@@ -1491,7 +1491,7 @@
</steps>
</testcase>
- <!--testcase>
+ <testcase>
<name>Single element direct read request</name>
<description>
When doing a simple read request with only a single direct address, the
@@ -1501,10 +1501,10 @@
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz</name>
- <address>00004040/00000008:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz</name>
+ <address>0x4040/0x8:BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
@@ -1524,18 +1524,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1553,11 +1553,11 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">8</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
@@ -1574,12 +1574,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -1590,7 +1590,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1608,38 +1608,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">1</length>
- <data dataType="byte" bitLength="8">0x01</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">8</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz>
<PlcResponseItem>
@@ -1652,35 +1634,34 @@
</values>
</PlcReadResponse>
</api-response>
- <delay>1000</delay>
</steps>
</testcase>
<testcase>
<name>Multi-element direct read request</name>
<description>
- When doing a simple read request with only direct addresses, but multiple
- ones, the unofficial multi-read method should be used to read all in one go.
+ When doing a read request with multiple direct addresses, the request is packed
+ into a single ADS sum command and the merged response is split up again.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>00004040/00000008:BOOL</address>
- </tag>
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz2</name>
- <address>00004040/00000012:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>0x4040/0x8:BOOL</address>
+ </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz2</name>
+ <address>0x4040/0xC:BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Ads Read Request">
+ <outgoing-plc-message name="Send Ads Sum Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
+ <length dataType="uint" bitLength="32">72</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -1693,20 +1674,20 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
+ <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
</commandId>
<initCommand dataType="bit" bitLength="1">false</initCommand>
<updCommand dataType="bit" bitLength="1">false</updCommand>
@@ -1718,22 +1699,39 @@
<response dataType="bit" bitLength="1">false</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
+ <length dataType="uint" bitLength="32">40</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
- </AdsReadRequest>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadWriteRequest>
+ <indexGroup dataType="uint" bitLength="32">61568</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">2</indexOffset>
+ <readLength dataType="uint" bitLength="32">10</readLength>
+ <writeLength dataType="uint" bitLength="32">24</writeLength>
+ <items isList="true">
+ <AdsMultiRequestItem>
+ <AdsMultiRequestItemRead>
+ <itemIndexGroup dataType="uint" bitLength="32">16448</itemIndexGroup>
+ <itemIndexOffset dataType="uint" bitLength="32">8</itemIndexOffset>
+ <itemReadLength dataType="uint" bitLength="32">1</itemReadLength>
+ </AdsMultiRequestItemRead>
+ </AdsMultiRequestItem>
+ <AdsMultiRequestItem>
+ <AdsMultiRequestItemRead>
+ <itemIndexGroup dataType="uint" bitLength="32">16448</itemIndexGroup>
+ <itemIndexOffset dataType="uint" bitLength="32">12</itemIndexOffset>
+ <itemReadLength dataType="uint" bitLength="32">1</itemReadLength>
+ </AdsMultiRequestItemRead>
+ </AdsMultiRequestItem>
+ </items>
+ <data dataType="byte" bitLength="0">0x</data>
+ </AdsReadWriteRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
-
</outgoing-plc-message>
- <incoming-plc-message name="Receive Ads Read Response">
+ <incoming-plc-message name="Receive Ads Sum Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">50</length>
@@ -1744,12 +1742,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -1760,7 +1758,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
</commandId>
@@ -1778,46 +1776,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadWriteResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">10</length>
+ <data dataType="byte" bitLength="80">0x00000000000000000101</data>
+ </AdsReadWriteResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">8</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz1>
- <hurz2>
- <DirectAdsField>
- <indexGroup dataType="uint" bitLength="32">4040</indexGroup>
- <indexOffset dataType="uint" bitLength="32">12</indexOffset>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </DirectAdsField>
- </hurz2>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
@@ -1838,29 +1810,28 @@
</values>
</PlcReadResponse>
</api-response>
- <delay>1000</delay>
</steps>
</testcase>
<testcase>
<name>Single element symbolic read request</name>
<description>
- When doing a simple read request with only a single symbolic address, which has not
- been resolved previously, first a resolution request has to be issued and the data
- from the response should be used in a second request to actually read the data.
+ A read request with a symbolic address is resolved offline against the symbol- and
+ data-type-tables loaded during connection setup, so only the direct read of the
+ resolved address goes on the wire.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Resolve Symbolic Address Request">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -1876,18 +1847,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -1905,140 +1876,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Resolve Symbolic Address Response">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">true</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">4</length>
- <data dataType="byte" bitLength="32">0x0100801b</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </incoming-plc-message>
- <outgoing-plc-message name="Send Ads Read Request">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">false</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </outgoing-plc-message>
<incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2046,12 +1897,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2062,7 +1913,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2076,47 +1927,30 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
@@ -2129,22 +1963,21 @@
<testcase>
<name>Single element symbolic read request (Address previously resolved)</name>
<description>
- When doing a simple read request with only a single symbolic address, which has
- been resolved previously, the data from the previous request should be used directly
- without re-resolving it.
+ Reading the same symbolic address twice resolves to the same direct address both
+ times without any additional resolution traffic on the wire.
</description>
<steps>
<api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Resolve Symbolic Address Request">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -2160,18 +1993,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2189,141 +2022,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
<AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61455</indexGroup>
- <indexOffset dataType="uint" bitLength="32">0</indexOffset>
- <length dataType="uint" bitLength="32">24</length>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
</AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Resolve Symbolic Address Response">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ_WRITE">9</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">true</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">1</invokeId>
- <data>
- <AdsData>
- <AdsReadWriteResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">4</length>
- <data dataType="byte" bitLength="32">0x0100801b</data>
- </AdsReadWriteResponse>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
- </incoming-plc-message>
- <outgoing-plc-message name="Send Ads Read Request">
- <AmsTCPPacket>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">44</length>
- <userdata>
- <AmsPacket>
- <targetAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">20</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
- <sourceAmsNetId>
- <AmsNetId>
- <octet1 dataType="uint" bitLength="8">192</octet1>
- <octet2 dataType="uint" bitLength="8">168</octet2>
- <octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
- <octet5 dataType="uint" bitLength="8">1</octet5>
- <octet6 dataType="uint" bitLength="8">1</octet6>
- </AmsNetId>
- </sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
- <commandId>
- <CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
- </commandId>
- <initCommand dataType="bit" bitLength="1">false</initCommand>
- <updCommand dataType="bit" bitLength="1">false</updCommand>
- <timestampAdded dataType="bit" bitLength="1">false</timestampAdded>
- <highPriorityCommand dataType="bit" bitLength="1">false</highPriorityCommand>
- <systemCommand dataType="bit" bitLength="1">false</systemCommand>
- <adsCommand dataType="bit" bitLength="1">true</adsCommand>
- <noReturn dataType="bit" bitLength="1">false</noReturn>
- <response dataType="bit" bitLength="1">false</response>
- <broadcast dataType="bit" bitLength="1">false</broadcast>
- <reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">12</length>
- <errorCode>
- <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
- </errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
- </AmsPacket>
- </userdata>
- </AmsTCPPacket>
-
- </outgoing-plc-message>
<incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2331,12 +2043,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2347,7 +2059,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2361,66 +2073,47 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">2</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">9</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
-
</incoming-plc-message>
<api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
</values>
</PlcReadResponse>
</api-response>
- <delay>500</delay>
- <api-request name="Receive a second Read Request for the same resource from application">
+ <api-request name="Receive Read Request from application">
<TestReadRequest>
<tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>main.f_trigDateiGelesen.M:BOOL</address>
- </tag>
+ <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
+ <name>hurz1</name>
+ <address>MAIN.hurz_Struct.hurz_BOOL</address>
+ </tag>
</tags>
</TestReadRequest>
</api-request>
- <outgoing-plc-message name="Send Ads Read Request directly using the preciously resolved address">
+ <outgoing-plc-message name="Send Ads Read Request">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
<length dataType="uint" bitLength="32">44</length>
@@ -2436,18 +2129,18 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">851</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">65534</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2465,24 +2158,20 @@
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">3</invokeId>
- <data>
- <AdsData>
- <AdsReadRequest>
- <indexGroup dataType="uint" bitLength="32">61445</indexGroup>
- <indexOffset dataType="uint" bitLength="32">461373441</indexOffset>
- <length dataType="uint" bitLength="32">1</length>
- </AdsReadRequest>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">10</invokeId>
+ <AdsReadRequest>
+ <indexGroup dataType="uint" bitLength="32">16448</indexGroup>
+ <indexOffset dataType="uint" bitLength="32">417176</indexOffset>
+ <length dataType="uint" bitLength="32">1</length>
+ </AdsReadRequest>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Receive Ads Read Response again">
+ <incoming-plc-message name="Receive Ads Read Response">
<AmsTCPPacket>
<reserved dataType="uint" bitLength="16">0</reserved>
- <length dataType="uint" bitLength="32">50</length>
+ <length dataType="uint" bitLength="32">41</length>
<userdata>
<AmsPacket>
<targetAmsNetId>
@@ -2490,12 +2179,12 @@
<octet1 dataType="uint" bitLength="8">192</octet1>
<octet2 dataType="uint" bitLength="8">168</octet2>
<octet3 dataType="uint" bitLength="8">23</octet3>
- <octet4 dataType="uint" bitLength="8">200</octet4>
+ <octet4 dataType="uint" bitLength="8">220</octet4>
<octet5 dataType="uint" bitLength="8">1</octet5>
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</targetAmsNetId>
- <targetAmsPort dataType="uint" bitLength="16">48898</targetAmsPort>
+ <targetAmsPort dataType="uint" bitLength="16">65534</targetAmsPort>
<sourceAmsNetId>
<AmsNetId>
<octet1 dataType="uint" bitLength="8">192</octet1>
@@ -2506,7 +2195,7 @@
<octet6 dataType="uint" bitLength="8">1</octet6>
</AmsNetId>
</sourceAmsNetId>
- <sourceAmsPort dataType="uint" bitLength="16">48898</sourceAmsPort>
+ <sourceAmsPort dataType="uint" bitLength="16">851</sourceAmsPort>
<commandId>
<CommandId dataType="uint" bitLength="16" stringRepresentation="ADS_READ">2</CommandId>
</commandId>
@@ -2520,47 +2209,30 @@
<response dataType="bit" bitLength="1">true</response>
<broadcast dataType="bit" bitLength="1">false</broadcast>
<reserved dataType="int" bitLength="7">0</reserved>
- <length dataType="uint" bitLength="32">18</length>
+ <length dataType="uint" bitLength="32">9</length>
<errorCode>
<ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
</errorCode>
- <invokeId dataType="uint" bitLength="32">3</invokeId>
- <data>
- <AdsData>
- <AdsReadResponse>
- <result>
- <ReturnCode dataType="uint" bitLength="32">0</ReturnCode>
- </result>
- <length dataType="uint" bitLength="32">10</length>
- <data dataType="byte" bitLength="80">0x00000000000000000101</data>
- </AdsReadResponse>
- </AdsData>
- </data>
+ <invokeId dataType="uint" bitLength="32">10</invokeId>
+ <AdsReadResponse>
+ <result>
+ <ReturnCode dataType="uint" bitLength="32" stringRepresentation="OK">0</ReturnCode>
+ </result>
+ <length dataType="uint" bitLength="32">1</length>
+ <data dataType="byte" bitLength="8">0x01</data>
+ </AdsReadResponse>
</AmsPacket>
</userdata>
</AmsTCPPacket>
</incoming-plc-message>
- <api-response name="Report Read Response to application again">
+ <api-response name="Report Read Response to application">
<PlcReadResponse>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <SymbolicAdsField>
- <symbolicAddress dataType="string" bitLength="200" encoding="UTF-8">main.f_trigDateiGelesen.M</symbolicAddress>
- <numberOfElements dataType="uint" bitLength="32">1</numberOfElements>
- <dataType dataType="string" bitLength="32" encoding="UTF-8">BOOL</dataType>
- </SymbolicAdsField>
- </hurz1>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
<values isList="true">
<hurz1>
<PlcResponseItem>
<code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
<value>
- <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+ <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
</value>
</PlcResponseItem>
</hurz1>
@@ -2568,6 +2240,6 @@
</PlcReadResponse>
</api-response>
</steps>
- </testcase-->
+ </testcase>
</test:driver-testsuite>