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/03/26 12:20:49 UTC

[plc4x] branch develop updated: - Implmented parsing of strings (Thanks to Etienne) - Extended the code-generation to be able to pass in string types (which have 3 arguments)

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 4a74ff5  - Implmented parsing of strings (Thanks to Etienne) - Extended the code-generation to be able to pass in string types (which have 3 arguments)
4a74ff5 is described below

commit 4a74ff526aeb57e978005e37c878fe55021462aa
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Mar 26 13:20:42 2020 +0100

    - Implmented parsing of strings (Thanks to Etienne)
    - Extended the code-generation to be able to pass in string types (which have 3 arguments)
---
 .../language/java/JavaLanguageTemplateHelper.java  | 114 ++++++++++++++++-----
 .../resources/templates/java/data-io-template.ftlh |  13 ++-
 .../org/apache/plc4x/java/api/value/PlcList.java   |   2 +-
 .../plc4x/java/api/value/PlcSimpleValue.java       |   2 +-
 .../org/apache/plc4x/java/api/value/PlcString.java |   6 ++
 .../org/apache/plc4x/java/api/value/PlcStruct.java |   2 +-
 .../org/apache/plc4x/java/api/value/PlcValue.java  |   2 +-
 .../plc4x/java/api/value/PlcValueAdapter.java      |   2 +-
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |  19 +++-
 .../plc4x/java/spi/generation/ReadBuffer.java      |  13 ++-
 .../java/spi/messages/DefaultPlcReadResponse.java  |  32 +++---
 .../java/spi/messages/DefaultPlcWriteRequest.java  |   2 +-
 .../plc4x/test/driver/DriverTestsuiteRunner.java   |   3 +-
 .../s7/src/main/resources/protocols/s7/s7.mspec    |   2 +
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |  18 ++++
 15 files changed, 176 insertions(+), 56 deletions(-)

diff --git a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index df7ce05..37f7490 100644
--- a/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/build-utils/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -584,7 +584,9 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             if(!(vl.getArgs().get(0) instanceof StringLiteral)) {
                 throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
             }
+            // Get the class and method name
             String methodName = ((StringLiteral) vl.getArgs().get(0)).getValue();
+            // Cut off the double-quptes
             methodName = methodName.substring(1, methodName.length() - 1);
             sb.append(methodName).append("(");
             for(int i = 1; i < vl.getArgs().size(); i++) {
@@ -595,17 +597,36 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                 if(arg instanceof VariableLiteral) {
                     VariableLiteral va = (VariableLiteral) arg;
                     // "io" is the default name of the reader argument which is always available.
-                    boolean isDeserializerArg = "io".equals(va.getName());
-                    if(parserArguments != null) {
+                    boolean isParserArg = "io".equals(va.getName());
+                    boolean isTypeArg = "_type".equals(va.getName());
+                    if(!isParserArg && !isTypeArg && parserArguments != null) {
                         for (Argument parserArgument : parserArguments) {
                             if (parserArgument.getName().equals(va.getName())) {
-                                isDeserializerArg = true;
+                                isParserArg = true;
                                 break;
                             }
                         }
                     }
-                    if(isDeserializerArg) {
+                    if(isParserArg) {
                         sb.append(va.getName() + ((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : ""));
+                    }
+                    // We have to manually evaluate the type information at code-generation time.
+                    else if(isTypeArg) {
+                        String part = va.getChild().getName();
+                        switch (part) {
+                            case "name":
+                                sb.append("\"").append(field.getTypeName()).append("\"");
+                                break;
+                            case "length":
+                                sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                                break;
+                            case "encoding":
+                                String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                                // Cut off the single quotes.
+                                encoding = encoding.substring(1, encoding.length() - 1);
+                                sb.append("\"").append(encoding).append("\"");
+                                break;
+                        }
                     } else {
                         sb.append(toVariableParseExpression(field, va, null));
                     }
@@ -639,7 +660,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         return vl.getName() + ((vl.getChild() != null) ? "." + toVariableExpressionRest(vl.getChild()) : "");
     }
 
-    private String toVariableSerializationExpression(TypedField field, Term term, Argument[] parserArguments) {
+    private String toVariableSerializationExpression(TypedField field, Term term, Argument[] serialzerArguments) {
         VariableLiteral vl = (VariableLiteral) term;
         if("STATIC_CALL".equals(vl.getName())) {
             StringBuilder sb = new StringBuilder();
@@ -658,9 +679,10 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                     VariableLiteral va = (VariableLiteral) arg;
                     // "io" and "_value" are always available in every parser.
                     boolean isSerializerArg = "io".equals(va.getName()) || "_value".equals(va.getName()) || "element".equals(va.getName());
-                    if(parserArguments != null) {
-                        for (Argument parserArgument : parserArguments) {
-                            if (parserArgument.getName().equals(va.getName())) {
+                    boolean isTypeArg = "_type".equals(va.getName());
+                    if(!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+                        for (Argument serializerArgument : serialzerArguments) {
+                            if (serializerArgument.getName().equals(va.getName())) {
                                 isSerializerArg = true;
                                 break;
                             }
@@ -668,6 +690,22 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                     }
                     if(isSerializerArg) {
                         sb.append(va.getName() + ((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : ""));
+                    } else if(isTypeArg) {
+                        String part = va.getChild().getName();
+                        switch (part) {
+                            case "name":
+                                sb.append("\"").append(field.getTypeName()).append("\"");
+                                break;
+                            case "length":
+                                sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                                break;
+                            case "encoding":
+                                String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                                // Cut off the single quotes.
+                                encoding = encoding.substring(1, encoding.length() - 1);
+                                sb.append("\"").append(encoding).append("\"");
+                                break;
+                        }
                     } else {
                         sb.append(toVariableSerializationExpression(field, va, null));
                     }
@@ -711,10 +749,11 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
 
                     if(arg instanceof VariableLiteral) {
                         VariableLiteral va = (VariableLiteral) arg;
-                        boolean isSerializerArg = false;
-                        if(parserArguments != null) {
-                            for (Argument parserArgument : parserArguments) {
-                                if (parserArgument.getName().equals(va.getName())) {
+                        boolean isSerializerArg = "io".equals(va.getName());
+                        boolean isTypeArg = "_type".equals(va.getName());
+                        if(!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+                            for (Argument serializerArgument : serialzerArguments) {
+                                if (serializerArgument.getName().equals(va.getName())) {
                                     isSerializerArg = true;
                                     break;
                                 }
@@ -722,6 +761,22 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                         }
                         if(isSerializerArg) {
                             sb.append(va.getName() + ((va.getChild() != null) ? "." + toVariableExpressionRest(va.getChild()) : ""));
+                        } else if(isTypeArg) {
+                            String part = va.getChild().getName();
+                            switch (part) {
+                                case "name":
+                                    sb.append("\"").append(field.getTypeName()).append("\"");
+                                    break;
+                                case "length":
+                                    sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+                                    break;
+                                case "encoding":
+                                    String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                                    // Cut off the single quotes.
+                                    encoding = encoding.substring(1, encoding.length() - 1);
+                                    sb.append("\"").append(encoding).append("\"");
+                                    break;
+                            }
                         } else {
                             sb.append(toVariableSerializationExpression(field, va, null));
                         }
@@ -734,14 +789,12 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             }
             return sb.toString();
         }
-        boolean isSerializerArg = false;
         // The synthetic checksumRawData is a local field and should not be accessed as bean property.
-        if(vl.getName().equals("checksumRawData")) {
-            isSerializerArg = true;
-        }
-        if(parserArguments != null) {
-            for (Argument parserArgument : parserArguments) {
-                if (parserArgument.getName().equals(vl.getName())) {
+        boolean isSerializerArg = "checksumRawData".equals(vl.getName()) || "_value".equals(vl.getName()) || "element".equals(vl.getName());
+        boolean isTypeArg = "_type".equals(vl.getName());
+        if(!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+            for (Argument serializerArgument : serialzerArguments) {
+                if (serializerArgument.getName().equals(vl.getName())) {
                     isSerializerArg = true;
                     break;
                 }
@@ -749,6 +802,21 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
         }
         if(isSerializerArg) {
             return vl.getName() + ((vl.getChild() != null) ? "." + toVariableExpressionRest(vl.getChild()) : "");
+        } else if(isTypeArg) {
+            String part = vl.getChild().getName();
+            switch (part) {
+                case "name":
+                    return"\"" + field.getTypeName() + "\"";
+                case "length":
+                    return"\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
+                case "encoding":
+                    String encoding = ((StringTypeReference) field.getType()).getEncoding();
+                    // Cut off the single quotes.
+                    encoding = encoding.substring(1, encoding.length() - 1);
+                    return"\"" + encoding + "\"";
+                default:
+                    return "";
+            }
         } else {
             return "_value." + toVariableExpressionRest(vl);
         }
@@ -759,7 +827,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
             ((vl.getChild() != null) ? "." + toVariableExpressionRest(vl.getChild()) : ""));
     }
 
-    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition) {
+    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, Argument[] parserArguments) {
         int sizeInBits = 0;
         StringBuilder sb = new StringBuilder("");
         for (Field field : complexTypeDefinition.getFields()) {
@@ -768,10 +836,10 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                 final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
                 switch (arrayField.getLoopType()) {
                     case COUNT:
-                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), null)).append(" * ").append(type.getSizeInBits()).append(") + ");
+                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
                         break;
                     case LENGTH:
-                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), null)).append(" * 8) + ");
+                        sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
                         break;
                     case TERMINATED:
                         // No terminated.
@@ -782,7 +850,7 @@ public class JavaLanguageTemplateHelper implements FreemarkerLanguageTemplateHel
                 final TypeReference type = typedField.getType();
                 if(field instanceof ManualField) {
                     ManualField manualField = (ManualField) field;
-                    sb.append("(").append(toSerializationExpression(null, manualField.getLengthExpression(), null)).append(") + ");
+                    sb.append("(").append(toSerializationExpression(null, manualField.getLengthExpression(), parserArguments)).append(") + ");
                 }
                 else if(type instanceof SimpleTypeReference) {
                     SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
diff --git a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
index d9a5a49..8591e2c 100644
--- a/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/data-io-template.ftlh
@@ -147,7 +147,7 @@ public class ${typeName}IO {
                     <#case "manual">
 
             // Manual Field (${field.name})
-            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)});
+            ${helper.getLanguageTypeNameForField(field)} ${field.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(field, field.parseExpression, type.parserArguments)?no_esc});
                         <#-- If a manual field is detected, the value returned by this is instantly treated as the value -->
                         <#switch case.name>
                             <#case "Time">
@@ -162,9 +162,8 @@ public class ${typeName}IO {
                             <#case "Struct">
             return new PlcStruct(${field.name});
                             <#break>
-                            <#-- Disable this for now -->
                             <#case "String">
-            //return new PlcStruct(${field.name});
+            return new PlcString(${field.name});
                             <#break>
                             <#default>
             return new Plc${case.name}(${field.name});
@@ -212,9 +211,9 @@ public class ${typeName}IO {
                     <#case "List">
             return new PlcList(Arrays.asList(value));
                     <#break>
-            <#-- Disable this for now -->
+            <#-- Disable this for now as Strings will only be parsed as manual fields -->
                     <#case "String">
-            //return new PlcStruct(_map);
+            //return new PlcString(_map);
                     <#break>
                     <#default>
             return new Plc${case.name}(value);
@@ -227,7 +226,7 @@ public class ${typeName}IO {
 <#if outputFlavor != "passive">
     public static WriteBuffer staticSerialize(PlcValue _value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeName(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         <#list type.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toSwitchExpression(type.switchField.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) </#if>{ // ${case.name}
-            WriteBuffer io = new WriteBuffer(${helper.getSizeInBits(case)} / 8 );
+            WriteBuffer io = new WriteBuffer(${helper.getSizeInBits(case, type.parserArguments)} / 8 );
             <#list case.fields as field>
                 <#switch field.typeName>
                     <#case "array">
@@ -243,7 +242,7 @@ public class ${typeName}IO {
                     <#break>
                     <#case "manual">
             // Manual Field (${field.name})
-            ${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)};
+            ${helper.toSerializationExpression(field, field.serializeExpression, type.parserArguments)?no_esc};
                     <#break>
                     <#case "reserved">
             // Reserved Field
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
index 5a43f11..6a25d2e 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
@@ -59,7 +59,7 @@ public class PlcList extends PlcValueAdapter {
 
     @Override
     @JsonIgnore
-    public int getNumberOfValues() {
+    public int getLength() {
         return listItems.size();
     }
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java
index 61ab586..ea49a0a 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcSimpleValue.java
@@ -38,7 +38,7 @@ public abstract class PlcSimpleValue<T> extends PlcValueAdapter {
 
     @Override
     @JsonIgnore
-    public int getNumberOfValues() {
+    public int getLength() {
         return 1;
     }
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcString.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcString.java
index b610237..5c4c8aa 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcString.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcString.java
@@ -76,6 +76,12 @@ public class PlcString extends PlcSimpleValue<String> {
 
     @Override
     @JsonIgnore
+    public int getLength() {
+        return value.length();
+    }
+
+    @Override
+    @JsonIgnore
     public String toString() {
         return "\"" + value + "\"";
     }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java
index 5534cef..929a62b 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcStruct.java
@@ -41,7 +41,7 @@ public class PlcStruct extends PlcValueAdapter {
 
     @Override
     @JsonIgnore
-    public int getNumberOfValues() {
+    public int getLength() {
         return 1;
     }
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
index bc6e319..10af797 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
@@ -124,7 +124,7 @@ public interface PlcValue {
 
     boolean isList();
 
-    int getNumberOfValues();
+    int getLength();
 
     PlcValue getIndex(int i);
 
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java
index c61a3ad..4c9af79 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueAdapter.java
@@ -243,7 +243,7 @@ public class PlcValueAdapter implements PlcValue {
 
     @Override
     @JsonIgnore
-    public int getNumberOfValues() {
+    public int getLength() {
         throw new PlcIncompatibleDatatypeException("");
     }
 
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index 8c38d0e..55369b2 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -19,7 +19,7 @@ under the License.
 package org.apache.plc4x.java.s7.utils;
 
 import org.apache.commons.lang3.NotImplementedException;
-import org.apache.plc4x.java.api.value.PlcTime;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
@@ -124,6 +124,23 @@ public class StaticHelper {
 
     }
 
+    public static String parseS7String(ReadBuffer io, String encoding) {
+        try {
+            // This is the maximum number of bytes a string can be long.
+            short maxLength = io.readUnsignedShort(8);
+            // This is the total length of the string on the PLC (Not necessarily the number of characters read)
+            short totalStringLength = io.readShort(8);
+            return io.readString(8 * totalStringLength, encoding);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeS7String(WriteBuffer io, PlcValue value, String encoding) {
+        // TODO: Need to implement the serialization or we can't write strings
+        throw new PlcRuntimeException("Not implemented yet");
+    }
+
     /**
      * converts incoming byte to an integer regarding used BCD format
      *
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 4954135..ed5a766 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -20,11 +20,13 @@
 package org.apache.plc4x.java.spi.generation;
 
 import com.github.jinahya.bit.io.ArrayByteInput;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.spi.generation.io.MyDefaultBitInput;
 
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.nio.charset.Charset;
 
 public class ReadBuffer {
 
@@ -266,7 +268,16 @@ public class ReadBuffer {
     }
 
     public String readString(int bitLength, String encoding) {
-        throw new UnsupportedOperationException("not implemented yet");
+        byte[] strBytes = new byte[bitLength/8];
+        for(int i= 0; i<bitLength/8 && hasMore(8); i++){
+            try {
+                strBytes[i] = readByte(8);
+            }
+            catch (Exception e){
+                throw new PlcRuntimeException(e);
+            }
+        }
+        return new String(strBytes, Charset.forName(encoding));
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
index 1372380..2d4dae0 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcReadResponse.java
@@ -75,7 +75,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            return plcList.getNumberOfValues();
+            return plcList.getLength();
         } else {
             return 1;
         }
@@ -127,7 +127,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Object> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Object> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getObject());
             }
@@ -168,7 +168,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Boolean> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Boolean> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getBoolean());
             }
@@ -209,7 +209,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Byte> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Byte> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getByte());
             }
@@ -250,7 +250,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Short> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Short> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getShort());
             }
@@ -291,7 +291,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Integer> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Integer> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getInteger());
             }
@@ -332,7 +332,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<BigInteger> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<BigInteger> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getBigInteger());
             }
@@ -373,7 +373,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Long> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Long> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getLong());
             }
@@ -414,7 +414,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Float> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Float> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getFloat());
             }
@@ -455,7 +455,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<Double> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<Double> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getDouble());
             }
@@ -496,7 +496,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<BigDecimal> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<BigDecimal> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getBigDecimal());
             }
@@ -537,7 +537,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<String> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<String> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getString());
             }
@@ -578,7 +578,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<LocalTime> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<LocalTime> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getTime());
             }
@@ -619,7 +619,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<LocalDate> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<LocalDate> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getDate());
             }
@@ -660,7 +660,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         PlcValue fieldInternal = getFieldInternal(name);
         if(fieldInternal instanceof PlcList) {
             PlcList plcList = (PlcList) fieldInternal;
-            List<LocalDateTime> items = new ArrayList<>(plcList.getNumberOfValues());
+            List<LocalDateTime> items = new ArrayList<>(plcList.getLength());
             for (PlcValue plcValue : plcList.getList()) {
                 items.add(plcValue.getDateTime());
             }
@@ -697,7 +697,7 @@ public class DefaultPlcReadResponse implements InternalPlcReadResponse, PlcReadR
         final PlcValue field = getFieldInternal(name);
         if(field instanceof PlcList) {
             PlcList plcList = (PlcList) field;
-            if(index > (plcList.getNumberOfValues() - 1)) {
+            if(index > (plcList.getLength() - 1)) {
                 return null;
             }
             return plcList.getIndex(index);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
index 45742a4..1caf576 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcWriteRequest.java
@@ -143,7 +143,7 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal
         final PlcValue value = fields.get(name).getValue();
         if(value instanceof PlcList) {
             PlcList list = (PlcList) value;
-            return list.getNumberOfValues();
+            return list.getLength();
         }
         return 1;
     }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
index d0ed288..6fde111 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
@@ -260,9 +260,8 @@ public class DriverTestsuiteRunner {
                     }
                     try {
                         final PlcResponse plcResponse = responseFuture.get(1000, TimeUnit.MILLISECONDS);
-                        // TODO: Make the API modules Serializable
                         final String serializedResponse = mapper.writeValueAsString(plcResponse);
-                        System.out.println(serializedResponse);
+                        // TODO: Implement ...
                     } catch(Exception e) {
                         throw new DriverTestsuiteException("Got no response within 1000ms.");
                     }
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index c8fe78f..c3edd82 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -338,8 +338,10 @@
         ['42' String
         ]
         ['43' String
+            [manual string 256 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, _type.encoding)' '_value.length + 2']
         ]
         ['44' String
+            [manual string 256 'UTF-16' 'value''STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, _type.encoding)' '(_value.length * 2) + 2']
         ]
 
         // -----------------------------------------
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index 7c085b9..55369b2 100644
--- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -19,6 +19,7 @@ under the License.
 package org.apache.plc4x.java.s7.utils;
 
 import org.apache.commons.lang3.NotImplementedException;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
@@ -123,6 +124,23 @@ public class StaticHelper {
 
     }
 
+    public static String parseS7String(ReadBuffer io, String encoding) {
+        try {
+            // This is the maximum number of bytes a string can be long.
+            short maxLength = io.readUnsignedShort(8);
+            // This is the total length of the string on the PLC (Not necessarily the number of characters read)
+            short totalStringLength = io.readShort(8);
+            return io.readString(8 * totalStringLength, encoding);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeS7String(WriteBuffer io, PlcValue value, String encoding) {
+        // TODO: Need to implement the serialization or we can't write strings
+        throw new PlcRuntimeException("Not implemented yet");
+    }
+
     /**
      * converts incoming byte to an integer regarding used BCD format
      *