You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/11/18 14:35:46 UTC

[plc4x] branch feature/plc4go updated: - Fixed the reading of strings and Wstrings (Introduced a similar type of string fields, which have a length attribute just like in S7)

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/plc4go by this push:
     new 62706e0  - Fixed the reading of strings and Wstrings (Introduced a similar type of string fields, which have a length attribute just like in S7)
62706e0 is described below

commit 62706e0abaf4455ffe0da2f1a64eed7c24bd6c53
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Nov 18 15:35:38 2020 +0100

    - Fixed the reading of strings and Wstrings (Introduced a similar type of string fields, which have a length attribute just like in S7)
---
 .../plc4x/java/ads/field/AdsFieldHandler.java      |   8 +-
 .../plc4x/java/ads/field/AdsStringField.java       |  25 ++++
 .../plc4x/java/ads/field/DirectAdsStringField.java | 126 +++++++++++++++++++++
 .../plc4x/java/ads/field/SymbolicAdsField.java     |   7 +-
 ...icAdsField.java => SymbolicAdsStringField.java} |  75 ++++--------
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  | 107 ++++++++++++-----
 .../apache/plc4x/java/ads/utils/StaticHelper.java  |  32 +++---
 .../plc4x/protocol/ads/ManualAdsDriverTest.java    |   8 +-
 .../plc4x/java/examples/helloplc4x/HelloPlc4x.java |  10 +-
 .../org/apache/plc4x/test/manual/ManualTest.java   |   1 -
 .../ads/src/main/resources/protocols/ads/ads.mspec |  16 ++-
 11 files changed, 290 insertions(+), 125 deletions(-)

diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
index 2b85eea..fdeaebd 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsFieldHandler.java
@@ -26,8 +26,12 @@ public class AdsFieldHandler implements PlcFieldHandler {
 
     @Override
     public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
-        if (DirectAdsField.matches(fieldQuery)) {
-            return DirectAdsField.of(fieldQuery);
+        if (DirectAdsStringField.matches(fieldQuery)) {
+            return DirectAdsStringField.of(fieldQuery);
+        } else if (DirectAdsField.matches(fieldQuery)) {
+            return SymbolicAdsField.of(fieldQuery);
+        } else if (SymbolicAdsStringField.matches(fieldQuery)) {
+            return SymbolicAdsStringField.of(fieldQuery);
         } else if (SymbolicAdsField.matches(fieldQuery)) {
             return SymbolicAdsField.of(fieldQuery);
         }
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsStringField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsStringField.java
new file mode 100644
index 0000000..92ab3db
--- /dev/null
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/AdsStringField.java
@@ -0,0 +1,25 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.ads.field;
+
+public interface AdsStringField extends AdsField {
+
+    int getStringLength();
+
+}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsStringField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsStringField.java
new file mode 100644
index 0000000..89d00bc
--- /dev/null
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/DirectAdsStringField.java
@@ -0,0 +1,126 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+package org.apache.plc4x.java.ads.field;
+
+import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * ADS address witch is defined by {@code indexGroup/indexOffset}. These values can be either supplied as int or hex
+ * representation.
+ */
+public class DirectAdsStringField extends DirectAdsField implements AdsStringField {
+
+    private static final Pattern RESOURCE_STRING_ADDRESS_PATTERN = Pattern.compile("^((0[xX](?<indexGroupHex>[0-9a-fA-F]+))|(?<indexGroup>\\d+))/((0[xX](?<indexOffsetHex>[0-9a-fA-F]+))|(?<indexOffset>\\d+)):(?<adsDataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numberOfElements>\\d)])?");
+
+    private final int stringLength;
+
+    public DirectAdsStringField(long indexGroup, long indexOffset, AdsDataType adsDataType, int stringLength, Integer numberOfElements) {
+        super(indexGroup, indexOffset, adsDataType, numberOfElements);
+        this.stringLength = stringLength;
+    }
+
+    public static DirectAdsStringField of(long indexGroup, long indexOffset, AdsDataType adsDataType, int stringLength, Integer numberOfElements) {
+        return new DirectAdsStringField(indexGroup, indexOffset, adsDataType, stringLength, numberOfElements);
+    }
+
+    public static DirectAdsStringField of(String address) {
+        Matcher matcher = RESOURCE_STRING_ADDRESS_PATTERN.matcher(address);
+        if (!matcher.matches()) {
+            throw new PlcInvalidFieldException(address, RESOURCE_STRING_ADDRESS_PATTERN, "{indexGroup}/{indexOffset}:{adsDataType}([numberOfElements])?");
+        }
+
+        String indexGroupStringHex = matcher.group("indexGroupHex");
+        String indexGroupString = matcher.group("indexGroup");
+
+        String indexOffsetStringHex = matcher.group("indexOffsetHex");
+        String indexOffsetString = matcher.group("indexOffset");
+
+        long indexGroup;
+        if (indexGroupStringHex != null) {
+            indexGroup = Long.parseLong(indexGroupStringHex, 16);
+        } else {
+            indexGroup = Long.parseLong(indexGroupString);
+        }
+
+        long indexOffset;
+        if (indexOffsetStringHex != null) {
+            indexOffset = Long.parseLong(indexOffsetStringHex, 16);
+        } else {
+            indexOffset = Long.parseLong(indexOffsetString);
+        }
+
+        String adsDataTypeString = matcher.group("adsDataType");
+        AdsDataType adsDataType = AdsDataType.valueOf(adsDataTypeString);
+
+        String stringLengthString = matcher.group("stringLength");
+        Integer stringLength = stringLengthString != null ? Integer.valueOf(stringLengthString) : null;
+
+        String numberOfElementsString = matcher.group("numberOfElements");
+        Integer numberOfElements = numberOfElementsString != null ? Integer.valueOf(numberOfElementsString) : null;
+
+        return new DirectAdsStringField(indexGroup, indexOffset, adsDataType, stringLength, numberOfElements);
+    }
+
+    public static boolean matches(String address) {
+        return RESOURCE_STRING_ADDRESS_PATTERN.matcher(address).matches();
+    }
+
+    @Override
+    public int getStringLength() {
+        return stringLength;
+    }
+
+    @Override
+    public String toString() {
+        return "DirectAdsStringField{" +
+            "indexGroup=" + getIndexGroup() +
+            ", indexOffset=" + getIndexOffset() +
+            ", stringLength=" + stringLength +
+            '}';
+    }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement(getClass().getSimpleName());
+        parent.appendChild(messageElement);
+        Element indexGroupElement = doc.createElement("indexGroup");
+        indexGroupElement.appendChild(doc.createTextNode(Long.toString(getIndexGroup())));
+        messageElement.appendChild(indexGroupElement);
+
+        Element indexOffsetElement = doc.createElement("indexOffset");
+        indexOffsetElement.appendChild(doc.createTextNode(Long.toString(getIndexOffset())));
+        messageElement.appendChild(indexOffsetElement);
+
+        Element numberOfElementsElement = doc.createElement("numberOfElements");
+        numberOfElementsElement.appendChild(doc.createTextNode(Integer.toString(getNumberOfElements())));
+        messageElement.appendChild(numberOfElementsElement);
+
+        Element datatypeElement = doc.createElement("dataType");
+        datatypeElement.appendChild(doc.createTextNode(getPlcDataType()));
+        messageElement.appendChild(datatypeElement);
+    }
+
+}
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
index d18305b..4455c59 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
@@ -40,13 +40,14 @@ public class SymbolicAdsField implements AdsField {
 
     private final int numberOfElements;
 
-    private SymbolicAdsField(String symbolicAddress, AdsDataType adsDataType, Integer numberOfElements) {
+    public SymbolicAdsField(String symbolicAddress, AdsDataType adsDataType, Integer numberOfElements) {
         this.symbolicAddress = Objects.requireNonNull(symbolicAddress);
         this.adsDataType = Objects.requireNonNull(adsDataType);
         this.numberOfElements = numberOfElements != null ? numberOfElements : 1;
         if (this.numberOfElements <= 0) {
             throw new IllegalArgumentException("numberOfElements must be greater then zero. Was " + this.numberOfElements);
         }
+
     }
 
     public static SymbolicAdsField of(String address) {
@@ -69,7 +70,7 @@ public class SymbolicAdsField implements AdsField {
         return SYMBOLIC_ADDRESS_PATTERN.matcher(address).matches();
     }
 
-    public String getSymbolicField() {
+    public String getSymbolicAddress() {
         return symbolicAddress;
     }
 
@@ -119,7 +120,7 @@ public class SymbolicAdsField implements AdsField {
         parent.appendChild(messageElement);
 
         Element symbolicAddressElement = doc.createElement("symbolicAddress");
-        symbolicAddressElement.appendChild(doc.createTextNode(getSymbolicField()));
+        symbolicAddressElement.appendChild(doc.createTextNode(getSymbolicAddress()));
         messageElement.appendChild(symbolicAddressElement);
 
         Element numberOfElementsElement = doc.createElement("numberOfElements");
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsStringField.java
similarity index 57%
copy from plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
copy to plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsStringField.java
index d18305b..554cf06 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsField.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/field/SymbolicAdsStringField.java
@@ -30,85 +30,50 @@ import java.util.regex.Pattern;
 /**
  * ADS address witch is defined by symbolic name (e.g. {@code Main.items[0]}).
  */
-public class SymbolicAdsField implements AdsField {
+public class SymbolicAdsStringField extends SymbolicAdsField implements AdsStringField {
 
-    private static final Pattern SYMBOLIC_ADDRESS_PATTERN = Pattern.compile("^(?<symbolicAddress>.+):(?<adsDataType>\\w+)(\\[(?<numberOfElements>\\d)])?");
+    private static final Pattern SYMBOLIC_ADDRESS_STRING_PATTERN = Pattern.compile("^(?<symbolicAddress>.+):(?<adsDataType>'STRING'|'WSTRING')\\((?<stringLength>\\d{1,3})\\)(\\[(?<numberOfElements>\\d)])?");
 
-    private final String symbolicAddress;
+    private final int stringLength;
 
-    private final AdsDataType adsDataType;
-
-    private final int numberOfElements;
-
-    private SymbolicAdsField(String symbolicAddress, AdsDataType adsDataType, Integer numberOfElements) {
-        this.symbolicAddress = Objects.requireNonNull(symbolicAddress);
-        this.adsDataType = Objects.requireNonNull(adsDataType);
-        this.numberOfElements = numberOfElements != null ? numberOfElements : 1;
-        if (this.numberOfElements <= 0) {
-            throw new IllegalArgumentException("numberOfElements must be greater then zero. Was " + this.numberOfElements);
-        }
+    private SymbolicAdsStringField(String symbolicAddress, AdsDataType adsDataType, int stringLength, Integer numberOfElements) {
+        super(symbolicAddress, adsDataType, numberOfElements);
+        this.stringLength = stringLength;
     }
 
-    public static SymbolicAdsField of(String address) {
-        Matcher matcher = SYMBOLIC_ADDRESS_PATTERN.matcher(address);
+    public static SymbolicAdsStringField of(String address) {
+        Matcher matcher = SYMBOLIC_ADDRESS_STRING_PATTERN.matcher(address);
         if (!matcher.matches()) {
-            throw new PlcInvalidFieldException(address, SYMBOLIC_ADDRESS_PATTERN, "{address}");
+            throw new PlcInvalidFieldException(address, SYMBOLIC_ADDRESS_STRING_PATTERN, "{address}");
         }
         String symbolicAddress = matcher.group("symbolicAddress");
 
         String adsDataTypeString = matcher.group("adsDataType");
         AdsDataType adsDataType = AdsDataType.valueOf(adsDataTypeString);
 
+        String stringLengthString = matcher.group("stringLength");
+        Integer stringLength = stringLengthString != null ? Integer.valueOf(stringLengthString) : null;
+
         String numberOfElementsString = matcher.group("numberOfElements");
         Integer numberOfElements = numberOfElementsString != null ? Integer.valueOf(numberOfElementsString) : null;
 
-        return new SymbolicAdsField(symbolicAddress, adsDataType, numberOfElements);
+        return new SymbolicAdsStringField(symbolicAddress, adsDataType, stringLength, numberOfElements);
     }
 
     public static boolean matches(String address) {
-        return SYMBOLIC_ADDRESS_PATTERN.matcher(address).matches();
-    }
-
-    public String getSymbolicField() {
-        return symbolicAddress;
-    }
-
-    @Override
-    public AdsDataType getAdsDataType() {
-        return adsDataType;
-    }
-
-    @Override
-    public String getPlcDataType() {
-        return adsDataType.toString();
-    }
-
-    @Override
-    public int getNumberOfElements() {
-        return numberOfElements;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof SymbolicAdsField)) {
-            return false;
-        }
-        SymbolicAdsField that = (SymbolicAdsField) o;
-        return Objects.equals(symbolicAddress, that.symbolicAddress);
+        return SYMBOLIC_ADDRESS_STRING_PATTERN.matcher(address).matches();
     }
 
     @Override
-    public int hashCode() {
-        return Objects.hash(symbolicAddress);
+    public int getStringLength() {
+        return stringLength;
     }
 
     @Override
     public String toString() {
-        return "SymbolicAdsField{" +
-            "symbolicAddress='" + symbolicAddress + '\'' +
+        return "SymbolicAdsStringField{" +
+            "symbolicAddress='" + getSymbolicAddress() + '\'' +
+            ", stringLength=" + stringLength +
             '}';
     }
 
@@ -119,7 +84,7 @@ public class SymbolicAdsField implements AdsField {
         parent.appendChild(messageElement);
 
         Element symbolicAddressElement = doc.createElement("symbolicAddress");
-        symbolicAddressElement.appendChild(doc.createTextNode(getSymbolicField()));
+        symbolicAddressElement.appendChild(doc.createTextNode(getSymbolicAddress()));
         messageElement.appendChild(symbolicAddressElement);
 
         Element numberOfElementsElement = doc.createElement("numberOfElements");
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
index 817215f..93990bf 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
@@ -18,15 +18,17 @@ under the License.
 */
 package org.apache.plc4x.java.ads.protocol;
 
-import org.apache.plc4x.java.ads.readwrite.types.ReturnCode;
 import org.apache.plc4x.java.ads.configuration.AdsConfiguration;
 import org.apache.plc4x.java.ads.field.AdsField;
+import org.apache.plc4x.java.ads.field.AdsStringField;
 import org.apache.plc4x.java.ads.field.DirectAdsField;
 import org.apache.plc4x.java.ads.field.SymbolicAdsField;
 import org.apache.plc4x.java.ads.readwrite.*;
 import org.apache.plc4x.java.ads.readwrite.io.DataItemIO;
+import org.apache.plc4x.java.ads.readwrite.types.AdsDataType;
 import org.apache.plc4x.java.ads.readwrite.types.CommandId;
 import org.apache.plc4x.java.ads.readwrite.types.ReservedIndexGroups;
+import org.apache.plc4x.java.ads.readwrite.types.ReturnCode;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
@@ -35,7 +37,7 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
@@ -51,8 +53,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.time.Duration;
-import java.util.*;
-import java.util.concurrent.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -119,9 +125,9 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             getDirectAddresses(readRequest.getFields());
 
         // If all addresses were already resolved we can send the request immediately.
-        if(directAdsFieldsFuture.isDone()) {
+        if (directAdsFieldsFuture.isDone()) {
             final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null);
-            if(fields != null) {
+            if (fields != null) {
                 return executeRead(readRequest, fields);
             } else {
                 final CompletableFuture<PlcReadResponse> errorFuture = new CompletableFuture<>();
@@ -139,7 +145,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         else {
             CompletableFuture<PlcReadResponse> delayedRead = new CompletableFuture<>();
             directAdsFieldsFuture.handle((directAdsFields, throwable) -> {
-                if(directAdsFields != null) {
+                if (directAdsFields != null) {
                     final CompletableFuture<PlcReadResponse> delayedResponse =
                         executeRead(readRequest, directAdsFields);
                     delayedResponse.handle((plcReadResponse, throwable1) -> {
@@ -175,8 +181,20 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
     protected CompletableFuture<PlcReadResponse> singleRead(PlcReadRequest readRequest, DirectAdsField directAdsField) {
         CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
 
-        int size = directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements();
-        AdsData adsData = new AdsReadRequest(directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), size);
+        long size;
+        if (directAdsField.getAdsDataType() == AdsDataType.STRING) {
+            // If an explicit size is given with the string, use this, if not use 256
+            size = (directAdsField instanceof  AdsStringField) ?
+                ((AdsStringField) directAdsField).getStringLength() + 1 : 81;
+        } else if (directAdsField.getAdsDataType() == AdsDataType.WSTRING) {
+            // If an explicit size is given with the string, use this, if not use 512
+            size = (directAdsField instanceof  AdsStringField) ?
+                ((long) ((AdsStringField) directAdsField).getStringLength() + 1) * 2: 162;
+        } else {
+            size = directAdsField.getAdsDataType().getNumBytes();
+        }
+        AdsData adsData = new AdsReadRequest(directAdsField.getIndexGroup(), directAdsField.getIndexOffset(),
+            size * directAdsField.getNumberOfElements());
         AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
             configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
             CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, getInvokeId(), adsData);
@@ -191,7 +209,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId())
             .unwrap(response -> (AdsReadResponse) response.getUserdata().getData())
             .handle(responseAdsData -> {
-                if(responseAdsData.getResult() == ReturnCode.OK) {
+                if (responseAdsData.getResult() == ReturnCode.OK) {
                     final PlcReadResponse plcReadResponse = convertToPlc4xReadResponse(readRequest, responseAdsData);
                     // Convert the response from the PLC into a PLC4X Response ...
                     future.complete(plcReadResponse);
@@ -211,7 +229,21 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         // Calculate the size of all fields together.
         // Calculate the expected size of the response data.
         long expectedResponseDataSize = directAdsFields.stream().mapToLong(
-            field -> (field.getAdsDataType().getNumBytes() * field.getNumberOfElements()) + 4).sum();
+            field -> {
+                long size;
+                if (field.getAdsDataType() == AdsDataType.STRING) {
+                    // If an explicit size is given with the string, use this, if not use 256
+                    size = (field instanceof  AdsStringField) ?
+                        ((AdsStringField) field).getStringLength() + 1 : 81;
+                } else if (field.getAdsDataType() == AdsDataType.WSTRING) {
+                    // If an explicit size is given with the string, use this, if not use 512
+                    size = (field instanceof  AdsStringField) ?
+                        ((long) ((AdsStringField) field).getStringLength() + 1) * 2: 162;
+                } else {
+                    size = field.getAdsDataType().getNumBytes();
+                }
+                return (size * field.getNumberOfElements()) + 4;
+            }).sum();
 
         // With multi-requests, the index-group is fixed and the index offset indicates the number of elements.
         AdsData adsData = new AdsReadWriteRequest(
@@ -235,7 +267,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId())
             .unwrap(response -> (AdsReadWriteResponse) response.getUserdata().getData())
             .handle(responseAdsData -> {
-                if(responseAdsData.getResult() == ReturnCode.OK) {
+                if (responseAdsData.getResult() == ReturnCode.OK) {
                     final PlcReadResponse plcReadResponse = convertToPlc4xReadResponse(readRequest, responseAdsData);
                     // Convert the response from the PLC into a PLC4X Response ...
                     future.complete(plcReadResponse);
@@ -271,12 +303,12 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
                 }
             }
         }
-        if(readBuffer != null) {
+        if (readBuffer != null) {
             Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
             for (String fieldName : readRequest.getFieldNames()) {
                 AdsField field = (AdsField) readRequest.getField(fieldName);
                 // If the response-code was anything but OK, we don't need to parse the payload.
-                if(responseCodes.get(fieldName) != PlcResponseCode.OK) {
+                if (responseCodes.get(fieldName) != PlcResponseCode.OK) {
                     values.put(fieldName, new ResponseItem<>(responseCodes.get(fieldName), null));
                 }
                 // If the response-code was ok, parse the data returned.
@@ -300,14 +332,21 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
 
     private ResponseItem<PlcValue> parsePlcValue(AdsField field, ReadBuffer readBuffer) {
         try {
+            int strLen = 0;
+            if (field.getAdsDataType() == AdsDataType.STRING) {
+                strLen = (field instanceof AdsStringField) ? ((AdsStringField) field).getStringLength() : 256;
+            } else if (field.getAdsDataType() == AdsDataType.WSTRING) {
+                strLen = (field instanceof AdsStringField) ? ((AdsStringField) field).getStringLength() : 512;
+            }
+            final int stringLength = strLen;
             if (field.getNumberOfElements() == 1) {
                 return new ResponseItem<>(PlcResponseCode.OK,
-                    DataItemIO.staticParse(readBuffer, field.getAdsDataType().getDataFormatName()));
+                    DataItemIO.staticParse(readBuffer, field.getAdsDataType().getDataFormatName(), stringLength));
             } else {
                 // Fetch all
                 final PlcValue[] resultItems = IntStream.range(0, field.getNumberOfElements()).mapToObj(i -> {
                     try {
-                        return DataItemIO.staticParse(readBuffer, field.getAdsDataType().getDataFormatName());
+                        return DataItemIO.staticParse(readBuffer, field.getAdsDataType().getDataFormatName(), stringLength);
                     } catch (ParseException e) {
                         LOGGER.warn("Error parsing field item of type: '{}' (at position {}})", field.getAdsDataType(), i, e);
                     }
@@ -328,9 +367,9 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             getDirectAddresses(writeRequest.getFields());
 
         // If all addresses were already resolved we can send the request immediately.
-        if(directAdsFieldsFuture.isDone()) {
+        if (directAdsFieldsFuture.isDone()) {
             final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null);
-            if(fields != null) {
+            if (fields != null) {
                 return executeWrite(writeRequest, fields);
             } else {
                 final CompletableFuture<PlcWriteResponse> errorFuture = new CompletableFuture<>();
@@ -348,7 +387,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         else {
             CompletableFuture<PlcWriteResponse> delayedWrite = new CompletableFuture<>();
             directAdsFieldsFuture.handle((directAdsFields, throwable) -> {
-                if(directAdsFields != null) {
+                if (directAdsFields != null) {
                     final CompletableFuture<PlcWriteResponse> delayedResponse =
                         executeWrite(writeRequest, directAdsFields);
                     delayedResponse.handle((plcReadResponse, throwable1) -> {
@@ -369,7 +408,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
     }
 
     protected CompletableFuture<PlcWriteResponse> executeWrite(PlcWriteRequest writeRequest,
-                                                             List<DirectAdsField> directAdsFields) {
+                                                               List<DirectAdsField> directAdsFields) {
         // Depending on the number of fields, use a single item request or a sum-request
         if (directAdsFields.size() == 1) {
             // Do a normal (single item) ADS Write Request
@@ -387,8 +426,12 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         final String fieldName = writeRequest.getFieldNames().iterator().next();
         final AdsField plcField = (AdsField) writeRequest.getField(fieldName);
         final PlcValue plcValue = writeRequest.getPlcValue(fieldName);
+        final int stringLength = (directAdsField.getAdsDataType() == AdsDataType.STRING) ?
+            plcValue.getString().length() + 1 : (directAdsField.getAdsDataType() == AdsDataType.WSTRING) ?
+            (plcValue.getString().length() + 1) * 2 : 0;
         try {
-            WriteBuffer writeBuffer = DataItemIO.staticSerialize(plcValue, plcField.getAdsDataType().getDataFormatName(), true);
+            WriteBuffer writeBuffer = DataItemIO.staticSerialize(plcValue,
+                plcField.getAdsDataType().getDataFormatName(), stringLength, true);
             AdsData adsData = new AdsWriteRequest(
                 directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), writeBuffer.getData());
             AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
@@ -434,8 +477,12 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         for (String fieldName : writeRequest.getFieldNames()) {
             final AdsField field = (AdsField) writeRequest.getField(fieldName);
             final PlcValue plcValue = writeRequest.getPlcValue(fieldName);
+            final int stringLength = (field.getAdsDataType() == AdsDataType.STRING) ?
+                plcValue.getString().length() + 1 : (field.getAdsDataType() == AdsDataType.WSTRING) ?
+                (plcValue.getString().length() + 1) * 2 : 0;
             try {
-                final WriteBuffer itemWriteBuffer = DataItemIO.staticSerialize(plcValue, field.getAdsDataType().getDataFormatName(), true);
+                final WriteBuffer itemWriteBuffer = DataItemIO.staticSerialize(plcValue,
+                    field.getAdsDataType().getDataFormatName(), stringLength, true);
                 int numBytes = itemWriteBuffer.getPos();
                 System.arraycopy(itemWriteBuffer.getData(), 0, writeBuffer, pos, numBytes);
                 pos += numBytes;
@@ -466,7 +513,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId())
             .unwrap(response -> (AdsReadWriteResponse) response.getUserdata().getData())
             .handle(responseAdsData -> {
-                if(responseAdsData.getResult() == ReturnCode.OK) {
+                if (responseAdsData.getResult() == ReturnCode.OK) {
                     final PlcWriteResponse plcWriteResponse = convertToPlc4xWriteResponse(writeRequest, responseAdsData);
                     // Convert the response from the PLC into a PLC4X Response ...
                     future.complete(plcWriteResponse);
@@ -557,7 +604,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
 
             // Complete the future asynchronously as soon as all fields are resolved.
             resolutionComplete.handleAsync((unused, throwable) -> {
-                if(throwable != null) {
+                if (throwable != null) {
                     return future.completeExceptionally(throwable.getCause());
                 } else {
                     List<DirectAdsField> directAdsFields = new ArrayList<>(fields.size());
@@ -589,7 +636,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
 
         AdsData adsData = new AdsReadWriteRequest(ReservedIndexGroups.ADSIGRP_SYM_HNDBYNAME.getValue(), 0,
             4, null,
-            getNullByteTerminatedArray(symbolicAdsField.getSymbolicField()));
+            getNullByteTerminatedArray(symbolicAdsField.getSymbolicAddress()));
         AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
             configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
             CommandId.ADS_READ_WRITE, DEFAULT_COMMAND_STATE, 0, getInvokeId(), adsData);
@@ -606,9 +653,9 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             .check(adsDataResponse -> adsDataResponse instanceof AdsReadWriteResponse)
             .unwrap(adsDataResponse -> (AdsReadWriteResponse) adsDataResponse)
             .handle(responseAdsData -> {
-                if(responseAdsData.getResult() != ReturnCode.OK) {
+                if (responseAdsData.getResult() != ReturnCode.OK) {
                     future.completeExceptionally(new PlcException("Couldn't retrieve handle for symbolic field " +
-                        symbolicAdsField.getSymbolicField() + " got return code " + responseAdsData.getResult().name()));
+                        symbolicAdsField.getSymbolicAddress() + " got return code " + responseAdsData.getResult().name()));
                 } else {
                     ReadBuffer readBuffer = new ReadBuffer(responseAdsData.getData(), true);
                     try {
@@ -636,11 +683,11 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
         long expectedResponseDataSize = symbolicAdsFields.size() * 12;
         // Concatenate the string part of each symbolic address into one concattenated string and get the bytes.
         byte[] addressData = symbolicAdsFields.stream().map(
-            SymbolicAdsField::getSymbolicField).collect(Collectors.joining("")).getBytes();
+            SymbolicAdsField::getSymbolicAddress).collect(Collectors.joining("")).getBytes();
         AdsData adsData = new AdsReadWriteRequest(ReservedIndexGroups.ADSIGRP_MULTIPLE_READ_WRITE.getValue(),
             symbolicAdsFields.size(), expectedResponseDataSize, symbolicAdsFields.stream().map(symbolicAdsField ->
             new AdsMultiRequestItemReadWrite(ReservedIndexGroups.ADSIGRP_SYM_HNDBYNAME.getValue(), 0,
-                4, symbolicAdsField.getSymbolicField().length())
+                4, symbolicAdsField.getSymbolicAddress().length())
         ).toArray(AdsMultiRequestItem[]::new), addressData);
         AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
             configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
@@ -700,7 +747,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
     protected long getInvokeId() {
         long invokeId = invokeIdGenerator.getAndIncrement();
         // If we've reached the max value for a 16 bit transaction identifier, reset back to 1
-        if(invokeIdGenerator.get() == 0xFFFFFFFF) {
+        if (invokeIdGenerator.get() == 0xFFFFFFFF) {
             invokeIdGenerator.set(1);
         }
         return invokeId;
diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
index 1ae2ca0..5622bac 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
@@ -30,39 +30,39 @@ import java.util.List;
 
 public class StaticHelper {
 
-    public static String parseAmsString(ReadBuffer io, String encoding) {
+    public static String parseAmsString(ReadBuffer io, int stringLength, String encoding) {
         try {
             if ("UTF-8".equalsIgnoreCase(encoding)) {
                 List<Byte> bytes = new ArrayList<>();
-                while (io.hasMore(8)) {
+                for(int i = 0; (i < stringLength) && io.hasMore(8); i++) {
                     final byte curByte = io.readByte(8);
                     if (curByte != 0) {
                         bytes.add(curByte);
                     } else {
-                        final byte[] byteArray = new byte[bytes.size()];
-                        for (int i = 0; i < bytes.size(); i++) {
-                            byteArray[i] = bytes.get(i);
-                        }
-                        return new String(byteArray, StandardCharsets.UTF_8);
+                        break;
                     }
                 }
-                throw new PlcRuntimeException("Reached the end of the input without finishing the string");
+                final byte[] byteArray = new byte[bytes.size()];
+                for (int i = 0; i < bytes.size(); i++) {
+                    byteArray[i] = bytes.get(i);
+                }
+                return new String(byteArray, StandardCharsets.UTF_8);
             } else if ("UTF-16".equalsIgnoreCase(encoding)) {
                 List<Byte> bytes = new ArrayList<>();
-                while (io.hasMore(16)) {
+                for(int i = 0; (i < stringLength) && io.hasMore(16); i++) {
                     final short curShort = io.readShort(16);
                     if (curShort != 0) {
                         bytes.add((byte) (curShort >>> 8));
                         bytes.add((byte) (curShort & 0xFF));
                     } else {
-                        final byte[] byteArray = new byte[bytes.size()];
-                        for (int i = 0; i < bytes.size(); i++) {
-                            byteArray[i] = bytes.get(i);
-                        }
-                        return new String(byteArray, StandardCharsets.UTF_16);
+                        break;
                     }
                 }
-                throw new PlcRuntimeException("Reached the end of the input without finishing the string");
+                final byte[] byteArray = new byte[bytes.size()];
+                for (int i = 0; i < bytes.size(); i++) {
+                    byteArray[i] = bytes.get(i);
+                }
+                return new String(byteArray, StandardCharsets.UTF_16);
             } else {
                 throw new PlcRuntimeException("Unsupported string encoding " + encoding);
             }
@@ -71,7 +71,7 @@ public class StaticHelper {
         }
     }
 
-    public static void serializeAmsString(WriteBuffer io, PlcValue value, Object encoding) {
+    public static void serializeAmsString(WriteBuffer io, PlcValue value, int stringLength, Object encoding) {
         // TODO: Need to implement the serialization or we can't write strings
         throw new PlcRuntimeException("Not implemented yet");
     }
diff --git a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
index 2df45f2..50cb24b 100644
--- a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
+++ b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
@@ -69,7 +69,7 @@ public class ManualAdsDriverTest extends ManualTest {
 
     public static void main(String[] args) throws Exception {
         ManualAdsDriverTest test = new ManualAdsDriverTest("ads:tcp://192.168.23.20?sourceAmsNetId=192.168.23.200.1.1&sourceAmsPort=65534&targetAmsNetId=192.168.23.20.1.1&targetAmsPort=851");
-        test.addTestCase("main.hurz_BOOL:BOOL", true);
+        /*test.addTestCase("main.hurz_BOOL:BOOL", true);
         test.addTestCase("main.hurz_BYTE:BYTE", Arrays.asList(false, false, true, false, true, false, true, false));
         test.addTestCase("main.hurz_WORD:WORD", Arrays.asList(true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false));
         test.addTestCase("main.hurz_DWORD:DWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false));
@@ -83,15 +83,15 @@ public class ManualAdsDriverTest extends ManualTest {
         test.addTestCase("main.hurz_ULINT:ULINT", 4242442424242424242L);
         test.addTestCase("main.hurz_REAL:REAL", 3.14159265359F);
         test.addTestCase("main.hurz_LREAL:LREAL", 2.71828182846D);
-        test.addTestCase("main.hurz_STRING:STRING", "hurz");
+        test.addTestCase("main.hurz_STRING:STRING", "hurz");*/
         test.addTestCase("main.hurz_WSTRING:WSTRING", "wolf");
-        test.addTestCase("main.hurz_TIME:TIME", "PT1.234S");
+        /*test.addTestCase("main.hurz_TIME:TIME", "PT1.234S");
         test.addTestCase("main.hurz_LTIME:LTIME", "PT24015H23M12.034002044S");
         test.addTestCase("main.hurz_DATE:DATE", "1978-03-28");
         test.addTestCase("main.hurz_TIME_OF_DAY:TIME_OF_DAY", "15:36:30.123");
         test.addTestCase("main.hurz_TOD:TOD", "16:17:18.123");
         test.addTestCase("main.hurz_DATE_AND_TIME:DATE_AND_TIME", "1996-05-06T15:36:30");
-        test.addTestCase("main.hurz_DT:DT", "1972-03-29T00:00");
+        test.addTestCase("main.hurz_DT:DT", "1972-03-29T00:00");*/
         test.run();
     }
 
diff --git a/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java b/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
index f5e40e6..f4db3e4 100644
--- a/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
+++ b/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
@@ -60,7 +60,7 @@ public class HelloPlc4x {
             // - Give the single item requested the alias name "value"
             PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
             for (int i = 0; i < options.getFieldAddress().length; i++) {
-                builder.addItem("value-" + i, options.getFieldAddress()[i]);
+                builder.addItem("value-" + options.getFieldAddress()[i], options.getFieldAddress()[i]);
             }
             PlcReadRequest readRequest = builder.build();
 
@@ -73,13 +73,13 @@ public class HelloPlc4x {
             // Simply iterating over the field names returned in the response.
             printResponse(syncResponse);
 
-            PlcValue asPlcValue = syncResponse.getAsPlcValue();
-            System.out.println(asPlcValue.toString());
+            /*PlcValue asPlcValue = syncResponse.getAsPlcValue();
+            System.out.println(asPlcValue.toString());*/
 
             //////////////////////////////////////////////////////////
             // Read asynchronously ...
             // Register a callback executed as soon as a response arrives.
-            logger.info("Asynchronous request ...");
+            /*logger.info("Asynchronous request ...");
             CompletionStage<? extends PlcReadResponse> asyncResponse = readRequest.execute();
             asyncResponse.whenComplete((readResponse, throwable) -> {
                 if (readResponse != null) {
@@ -87,7 +87,7 @@ public class HelloPlc4x {
                 } else {
                     logger.error("An error occurred: " + throwable.getMessage(), throwable);
                 }
-            });
+            });*/
 
             // Give the async request a little time...
             TimeUnit.MILLISECONDS.sleep(1000);
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
index c9110ec..0c549d4 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.Assertions;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
 public abstract class ManualTest {
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index 508dcd0..2e49132 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -386,7 +386,7 @@
     [array int 8 'data' count 'sampleSize']
 ]
 
-[dataIo 'DataItem' [string 'dataFormatName']
+[dataIo 'DataItem' [string 'dataFormatName', int 32 'stringLength']
     [typeSwitch 'dataFormatName'
         // -----------------------------------------
         // Bit
@@ -464,12 +464,10 @@
 //            [simple string 16 'UTF-16' 'value']
         ]
         ['IEC61131_STRING' STRING
-            [manual   string  'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
-            [reserved uint 32 '0x00000000']
+            [manual   string  'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, stringLength, _type.encoding)' 'stringLength + 1']
         ]
         ['IEC61131_WSTRING' STRING
-            [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, _type.encoding)' '_value.length + 2']
-            [reserved uint 64 '0x00000000']
+            [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", io, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", io, _value, stringLength, _type.encoding)' '(stringLength * 2) + 2']
         ]
 
         // -----------------------------------------
@@ -547,10 +545,10 @@
     // -----------------------------------------
     // Characters & Strings
     // -----------------------------------------
-    [CHAR       ['1',  'IEC61131_CHAR']]
-    [WCHAR      ['2',  'IEC61131_WCHAR']]
-    [STRING     ['9',  'IEC61131_STRING']]
-    [WSTRING    ['18', 'IEC61131_WSTRING']]
+    [CHAR       ['1',   'IEC61131_CHAR']]
+    [WCHAR      ['2',   'IEC61131_WCHAR']]
+    [STRING     ['256', 'IEC61131_STRING']]
+    [WSTRING    ['512', 'IEC61131_WSTRING']]
     // -----------------------------------------
     // Dates & Times
     // -----------------------------------------