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 2021/11/03 14:45:05 UTC

[plc4x] branch feature/mspec-ng updated: - Refactored the way the STATIC_CALL operates to no longer require a java package name.

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

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


The following commit(s) were added to refs/heads/feature/mspec-ng by this push:
     new 3b642dd  - Refactored the way the STATIC_CALL operates to no longer require a java package name.
3b642dd is described below

commit 3b642dd5947df277c2b64ad46328f8011e53ac55
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Nov 3 15:44:49 2021 +0100

    - Refactored the way the STATIC_CALL operates to no longer require a java package name.
---
 code-generation/language-c/pom.xml                 |    1 +
 .../plc4x/language/c/CLanguageTemplateHelper.java  |   34 +-
 code-generation/language-go/pom.xml                |    1 +
 .../language/go/GoLanguageTemplateHelper.java      |   31 +-
 code-generation/language-java/pom.xml              |    2 +-
 .../language/java/JavaLanguageTemplateHelper.java  |    8 +
 .../resources/templates/java/io-template.java.ftlh |    6 +-
 .../plc4go/ads/readwrite/model/DataItem.go         |    8 +-
 .../model/{AdsStaticHelper.go => StaticHelper.go}  |    4 +-
 .../df1/readwrite/model/DF1SymbolMessageFrame.go   |    4 +-
 .../readwrite/model/DF1UnprotectedReadResponse.go  |    8 +-
 .../model/{Df1StaticHelper.go => StaticHelper.go}  |   10 +-
 ...f1StaticHelper_test.go => StaticHelper_test.go} |    2 +-
 .../{FirmataStaticHelper.go => StaticHelper.go}    |    8 +-
 .../model/SysexCommandReportFirmwareResponse.go    |    8 +-
 .../s7/readwrite/model/AssociatedValueType.go      |    8 +-
 .../internal/plc4go/s7/readwrite/model/DataItem.go |   16 +-
 .../plc4go/s7/readwrite/model/DateAndTime.go       |   28 +-
 .../plc4go/s7/readwrite/model/S7EventHelper.go     |   52 -
 .../model/{S7StaticHelper.go => StaticHelper.go}   |   64 +-
 .../ads/{ => readwrite}/utils/StaticHelper.java    |    2 +-
 .../utils/StaticHelper.java}                       |    4 +-
 .../canopen/transport/CANOpenFrameDataHandler.java |    4 +-
 .../transport/IdentityCANOpenFrameBuilder.java     |    4 +-
 .../utils/{FirmataUtils.java => StaticHelper.java} |    2 +-
 .../{ => readwrite}/utils/StaticHelper.java        |    2 +-
 .../java/s7/readwrite/utils/StaticHelper.java      | 2052 ++++++++++++++++++++
 .../apache/plc4x/java/s7/utils/S7EventHelper.java  | 1846 ------------------
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |  249 ---
 .../plc4x/java/spi/codegen/FieldCommons.java       |   12 +-
 .../spi/codegen/fields/FieldReaderFactory.java     |   10 +-
 .../java/spi/codegen/fields/FieldReaderManual.java |   11 +-
 .../spi/codegen/fields/FieldReaderManualArray.java |    5 +-
 .../plc4x/java/spi/codegen/io/ByteOrderAware.java} |   17 +-
 .../plc4x/java/spi/codegen/io/DataReader.java      |    7 +-
 .../java/spi/codegen/io/DataReaderFactory.java     |    5 +
 .../plc4x/java/spi/codegen/io/ParseSupplier.java}  |   16 +-
 .../plc4x/java/spi/generation/ReadBuffer.java      |    8 +-
 .../readwrite/utils/StaticHelper.java}             |    4 +-
 pom.xml                                            |    2 +
 .../ads/src/main/resources/protocols/ads/ads.mspec |    4 +-
 .../src/main/resources/protocols/can/canopen.mspec |    4 +-
 .../df1/src/main/resources/protocols/df1/df1.mspec |    4 +-
 .../main/resources/protocols/firmata/firmata.mspec |    2 +-
 .../resources/protocols/profinet/profinet.mspec    |    6 +-
 .../s7/src/main/resources/protocols/s7/s7.mspec    |   26 +-
 .../main/resources/protocols/can/socketcan.mspec   |    8 +-
 .../utils/StaticHelper.java}                       |    4 +-
 .../asciidoc/developers/code-gen/protocol/df1.adoc |    4 +-
 49 files changed, 2276 insertions(+), 2351 deletions(-)

diff --git a/code-generation/language-c/pom.xml b/code-generation/language-c/pom.xml
index 2a8f589..314846f 100644
--- a/code-generation/language-c/pom.xml
+++ b/code-generation/language-c/pom.xml
@@ -50,6 +50,7 @@
               <goal>verify</goal>
             </goals>
             <configuration>
+              <skipInvocation>${skip-code-generation-tests}</skipInvocation>
               <debug>true</debug>
               <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
               <projectsDirectory>src/test/resources</projectsDirectory>
diff --git a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
index 756587b..510e590 100644
--- a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
+++ b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
@@ -27,7 +27,6 @@ import org.apache.plc4x.plugins.codegenerator.types.fields.*;
 import org.apache.plc4x.plugins.codegenerator.types.references.*;
 import org.apache.plc4x.plugins.codegenerator.types.terms.*;
 
-import javax.swing.text.html.Option;
 import java.util.*;
 import java.util.function.Function;
 
@@ -845,16 +844,12 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
      */
     private String toStaticCallVariableParseExpression(TypeDefinition baseType, Field field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
         tracer = tracer.dive("STATIC_CALL");
-        if (!variableLiteral.getArgs().isPresent()) {
-            throw new FreemarkerException("'STATIC_CALL' needs at least one args");
-        }
-        List<Term> terms = variableLiteral.getArgs().get();
-        if (!(terms.get(0) instanceof StringLiteral)) {
-            throw new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
-        }
-        String functionName = ((StringLiteral) terms.get(0)).getValue();
-        // We'll cut off the java package structure and just take the segment after the last "."
-        functionName = functionName.substring(functionName.lastIndexOf('.') + 1);
+        List<Term> terms = variableLiteral.getArgs().orElseThrow(() -> new FreemarkerException("'STATIC_CALL' needs at least one args"));
+        String functionName = terms.get(0).asLiteral()
+            .orElseThrow(()-> new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a Literal"))
+            .asStringLiteral()
+            .orElseThrow(()-> new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral"))
+            .getValue();
         // But to make the function name unique, well add the driver prefix to it.
         StringBuilder sb = new StringBuilder(getCTypeName(functionName));
         if (terms.size() > 1) {
@@ -936,7 +931,6 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
                     if (!(typedField.getType() instanceof StringTypeReference)) {
                         throw new FreemarkerException("Can only access 'encoding' for string types.");
                     }
-                    StringTypeReference stringTypeReference = (StringTypeReference) typedField.getType();
                     final Term encodingTerm = field.getEncoding().orElse(new DefaultStringLiteral("UTF-8"));
                     if (!(encodingTerm instanceof StringLiteral)) {
                         throw new RuntimeException("Encoding must be a quoted string value");
@@ -1053,16 +1047,12 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
 
     private String toStaticCallSerializationExpression(TypeDefinition baseType, Field field, List<Argument> serializerArguments, VariableLiteral vl, Tracer tracer) {
         tracer = tracer.dive("toStaticCallSerializationExpression");
-        if (!vl.getArgs().isPresent()) {
-            throw new FreemarkerException("'STATIC_CALL' needs at least one attribute");
-        }
-        List<Term> args = vl.getArgs().get();
-        if (!(args.get(0) instanceof StringLiteral)) {
-            throw new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
-        }
-        String functionName = ((StringLiteral) args.get(0)).getValue();
-        // We'll cut off the java package structure and just take the segment after the last "."
-        functionName = functionName.substring(functionName.lastIndexOf('.') + 1);
+        List<Term> args = vl.getArgs().orElseThrow(() -> new FreemarkerException("'STATIC_CALL' needs at least one attribute"));
+        String functionName = args.get(0).asLiteral()
+            .orElseThrow(()-> new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a Literal"))
+            .asStringLiteral()
+            .orElseThrow(()-> new FreemarkerException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral"))
+            .getValue();
         // But to make the function name unique, well add the driver prefix to it.
         StringBuilder sb = new StringBuilder(getCTypeName(functionName));
         sb.append("(");
diff --git a/code-generation/language-go/pom.xml b/code-generation/language-go/pom.xml
index d73e417..c5fcddf 100644
--- a/code-generation/language-go/pom.xml
+++ b/code-generation/language-go/pom.xml
@@ -50,6 +50,7 @@
               <goal>verify</goal>
             </goals>
             <configuration>
+              <skipInvocation>${skip-code-generation-tests}</skipInvocation>
               <debug>true</debug>
               <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
               <projectsDirectory>src/test/resources</projectsDirectory>
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 3afe851..dab1a03 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
@@ -664,7 +664,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         //else if (isVariableLiteralImplicitField(vl)) {
         //    tracer = tracer.dive("implicit");
         //    return tracer + (serialize ? vl.getName() : vl.getName()) + ((vl.getChild() != null) ?
-        //        "." + StringUtils.capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
+        //        "." + capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
         //}
         // If we are accessing implicit fields, we need to rely on a local variable instead.
 
@@ -712,14 +712,14 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
                         .filter(curField -> (curField instanceof DiscriminatorField) && ((DiscriminatorField) curField).getName().equals(childProperty))
                         .findFirst();
                     if (matchingDiscriminatorField.isPresent()) {
-                        return tracer + "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + variableLiteral.getName() + ").Child." + StringUtils.capitalize(childProperty) + "()";
+                        return tracer + "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + variableLiteral.getName() + ").Child." + capitalize(childProperty) + "()";
                     }
                     // TODO: is this really meant to fall through?
                     tracer = tracer.dive("we fell through the complex complex");
                 } else if (typeDefinition instanceof EnumTypeDefinition) {
                     tracer = tracer.dive("enum");
-                    return tracer + (serialize ? "m." + StringUtils.capitalize(variableLiteral.getName()) : variableLiteral.getName()) +
-                        "." + StringUtils.capitalize(variableLiteral.getChild().orElseThrow(() -> new RuntimeException("enum needs a child")).getName()) + "()";
+                    return tracer + (serialize ? "m." + capitalize(variableLiteral.getName()) : variableLiteral.getName()) +
+                        "." + capitalize(variableLiteral.getChild().orElseThrow(() -> new RuntimeException("enum needs a child")).getName()) + "()";
                 }
             }
             // TODO: is this really meant to fall through?
@@ -749,9 +749,9 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             // We have a index call
             indexCall = "[" + variableLiteral.getIndex() + "]";
         }
-        return tracer + (serialize ? "m." + StringUtils.capitalize(variableLiteral.getName()) : variableLiteral.getName()) + indexCall +
+        return tracer + (serialize ? "m." + capitalize(variableLiteral.getName()) : variableLiteral.getName()) + indexCall +
             variableLiteral.getChild()
-                .map(child -> "." + StringUtils.capitalize(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess)))
+                .map(child -> "." + capitalize(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess)))
                 .orElse("");
     }
 
@@ -843,13 +843,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             .asStringLiteral()
             .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
             getValue();
-        // Remove all the previous parts prior to the Class name (Which starts with an uppercase letter)
-        while (staticCall.contains(".") && !StringUtils.isAllUpperCase(staticCall.substring(0, 1))) {
-            staticCall = staticCall.substring(staticCall.indexOf(".") + 1);
-        }
-        String className = staticCall.substring(0, staticCall.indexOf("."));
-        String methodName = staticCall.substring(staticCall.indexOf(".") + 1);
-        sb.append(className).append(StringUtils.capitalize(methodName)).append("(");
+        sb.append(capitalize(staticCall)).append("(");
         for (int i = 1; i < arguments.size(); i++) {
             Term arg = arguments.get(i);
             if (i > 1) {
@@ -927,7 +921,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
         }
         sb.append(typeLiteral.getName());
         sb.append("(").append(toVariableExpression(field, typeReference, firstArgument, parserArguments, serializerArguments, serialize, suppressPointerAccess)).append(")");
-        return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + StringUtils.capitalize(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess))).orElse("");
+        return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + capitalize(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess))).orElse("");
     }
 
     private String toOptionalVariableExpression(Field field, TypeReference typeReference, VariableLiteral variableLiteral, List<Argument> parserArguments, List<Argument> serializerArguments, boolean suppressPointerAccess, Tracer tracer) {
@@ -939,7 +933,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
     private String toConstantVariableExpression(Field field, TypeReference typeReference, VariableLiteral variableLiteral, List<Argument> parserArguments, List<Argument> serializerArguments, boolean suppressPointerAccess, Tracer tracer) {
         tracer = tracer.dive("enum constant");
         VariableLiteral child = variableLiteral.getChild().orElseThrow(IllegalStateException::new);
-        return tracer + variableLiteral.getName() + "." + StringUtils.capitalize(child.getName()) + "()" +
+        return tracer + variableLiteral.getName() + "." + capitalize(child.getName()) + "()" +
             child.getChild().map(childChild -> "." + toVariableExpression(field, typeReference, childChild, parserArguments, serializerArguments, false, suppressPointerAccess)).orElse("");
     }
 
@@ -952,7 +946,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
 
     private String toLengthVariableExpression(Field field, VariableLiteral variableLiteral, boolean serialize, Tracer tracer) {
         tracer = tracer.dive("length");
-        return tracer + (serialize ? ("len(m." + StringUtils.capitalize(variableLiteral.getName()) + ")") : ("(" + variableLiteral.getName() + ")"));
+        return tracer + (serialize ? ("len(m." + capitalize(variableLiteral.getName()) + ")") : ("(" + variableLiteral.getName() + ")"));
     }
 
     private String toValueVariableExpression(Field field, TypeReference typeReference, VariableLiteral variableLiteral, List<Argument> parserArguments, List<Argument> serializerArguments, boolean serialize, boolean suppressPointerAccess, Tracer tracer) {
@@ -1348,4 +1342,9 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp
             })
             .orElse(false);
     }
+
+    public String capitalize(String str) {
+        return StringUtils.capitalize(str);
+    }
+
 }
diff --git a/code-generation/language-java/pom.xml b/code-generation/language-java/pom.xml
index fcbe988..7a90c16 100644
--- a/code-generation/language-java/pom.xml
+++ b/code-generation/language-java/pom.xml
@@ -50,6 +50,7 @@
               <goal>verify</goal>
             </goals>
             <configuration>
+              <skipInvocation>${skip-code-generation-tests}</skipInvocation>
               <!-- These option allow that openjdk >=16 can run the google-code-format -->
               <!-- TODO: Add this to a self-activating maven profile -->
               <!--mavenOpts>
@@ -69,7 +70,6 @@
                 <extraArtifact>org.apache.plc4x.plugins:plc4x-maven-plugin:${plc4x-code-generation.version}</extraArtifact>
                 <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-protocol-base:${plc4x-code-generation.version}</extraArtifact>
                 <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
-                <extraArtifact>org.apache.plc4x.plugins:plc4x-code-generation-types-base:${plc4x-code-generation.version}</extraArtifact>
               </extraArtifacts>
               <pomIncludes>
                 <pomInclude>*/pom.xml</pomInclude>
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 1fae41d..dad6319 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -51,6 +51,10 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         this.options = options;
     }
 
+    public String packageName() {
+        return packageName(protocolName, "java", flavorName);
+    }
+
     public String packageName(String protocolName, String languageName, String languageFlavorName) {
         return Optional.ofNullable(options.get("package")).orElseGet(() ->
             "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
@@ -675,6 +679,8 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         if (arguments.size() < 1) {
             throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
         }
+        // TODO: make it as static import with a emitImport so if a static call is present a "utils" package must be present in the import
+        sb.append(packageName()).append(".utils.StaticHelper.");
         // Get the class and method name
         String methodName = arguments.get(0).asLiteral()
             .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
@@ -855,6 +861,8 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         if (arguments.size() < 1) {
             throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
         }
+        // TODO: make it as static import with a emitImport so if a static call is present a "utils" package must be present in the import
+        sb.append(packageName()).append(".utils.StaticHelper.");
         // Get the class and method name
         String methodName = arguments.get(0).asLiteral()
             .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
index edc9cda..8782dd9 100644
--- a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -199,7 +199,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#assign typedField = field.asTypedField().orElseThrow()>
         <#assign namedField = field.asNamedField().orElseThrow()>
 
-        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", "${helper.getTypeDefinitionForTypeReference(enumField.type).name}", new DataReaderEnumDefault<>(${helper.getTypeDefinitionForTypeReference(enumField.type).name}::firstEnumForField${enumField.fieldName?cap_first}, ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, enumField.fieldName))}));
+        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", "${helper.getTypeDefinitionForTypeReference(enumField.type).name}", readEnum(${helper.getTypeDefinitionForTypeReference(enumField.type).name}::firstEnumForField${enumField.fieldName?cap_first}, ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, enumField.fieldName))}));
         <#break>
     <#case "implicit">
         <#assign implicitField = field.asImplicitField().orElseThrow()>
@@ -224,9 +224,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
         <#assign typedField = field.asTypedField().orElseThrow()>
         <#assign namedField = field.asNamedField().orElseThrow()>
 
-        readBuffer.pullContext("${manualField.name}");
-        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)});
-        readBuffer.closeContext("${manualField.name}");
+        ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = readManualField("${namedField.name}", readBuffer, () -> (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)}));
         <#break>
     <#case "optional">
         <#assign optionalField = field.asOptionalField().orElseThrow()>
diff --git a/plc4go/internal/plc4go/ads/readwrite/model/DataItem.go b/plc4go/internal/plc4go/ads/readwrite/model/DataItem.go
index 377e35e..40df0d4 100644
--- a/plc4go/internal/plc4go/ads/readwrite/model/DataItem.go
+++ b/plc4go/internal/plc4go/ads/readwrite/model/DataItem.go
@@ -184,7 +184,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataFormatName string, stringLen
 	case dataFormatName == "IEC61131_STRING": // STRING
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseAmsString(readBuffer, stringLength, "UTF-8")
+		value, _valueErr := ParseAmsString(readBuffer, stringLength, "UTF-8")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -193,7 +193,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataFormatName string, stringLen
 	case dataFormatName == "IEC61131_WSTRING": // STRING
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseAmsString(readBuffer, stringLength, "UTF-16")
+		value, _valueErr := ParseAmsString(readBuffer, stringLength, "UTF-16")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -357,14 +357,14 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, value api.PlcValue, dataFo
 	case dataFormatName == "IEC61131_STRING": // STRING
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeAmsString(writeBuffer, value, stringLength, "UTF-8")
+		_valueErr := SerializeAmsString(writeBuffer, value, stringLength, "UTF-8")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
 	case dataFormatName == "IEC61131_WSTRING": // STRING
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeAmsString(writeBuffer, value, stringLength, "UTF-16")
+		_valueErr := SerializeAmsString(writeBuffer, value, stringLength, "UTF-16")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
diff --git a/plc4go/internal/plc4go/ads/readwrite/model/AdsStaticHelper.go b/plc4go/internal/plc4go/ads/readwrite/model/StaticHelper.go
similarity index 84%
rename from plc4go/internal/plc4go/ads/readwrite/model/AdsStaticHelper.go
rename to plc4go/internal/plc4go/ads/readwrite/model/StaticHelper.go
index b558c3a..37c4258 100644
--- a/plc4go/internal/plc4go/ads/readwrite/model/AdsStaticHelper.go
+++ b/plc4go/internal/plc4go/ads/readwrite/model/StaticHelper.go
@@ -24,7 +24,7 @@ import (
 	"github.com/apache/plc4x/plc4go/pkg/plc4go/values"
 )
 
-func StaticHelperParseAmsString(io utils.ReadBuffer, stringLength int32, encoding string) (string, error) {
+func ParseAmsString(io utils.ReadBuffer, stringLength int32, encoding string) (string, error) {
 	var multiplier int32
 	switch encoding {
 	case "UTF-8":
@@ -35,7 +35,7 @@ func StaticHelperParseAmsString(io utils.ReadBuffer, stringLength int32, encodin
 	return io.ReadString("", uint32(stringLength*multiplier))
 }
 
-func StaticHelperSerializeAmsString(io utils.WriteBuffer, value values.PlcValue, stringLength int32, encoding string) error {
+func SerializeAmsString(io utils.WriteBuffer, value values.PlcValue, stringLength int32, encoding string) error {
 	var multiplier int32
 	switch encoding {
 	case "UTF-8":
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/DF1SymbolMessageFrame.go b/plc4go/internal/plc4go/df1/readwrite/model/DF1SymbolMessageFrame.go
index dd15810..32f1583 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/DF1SymbolMessageFrame.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/DF1SymbolMessageFrame.go
@@ -175,7 +175,7 @@ func DF1SymbolMessageFrameParse(readBuffer utils.ReadBuffer) (*DF1Symbol, error)
 		if _checksumRefErr != nil {
 			return nil, errors.Wrap(_checksumRefErr, "Error parsing 'checksum' field")
 		}
-		checksum, _checksumErr := DF1UtilsCrcCheck(destinationAddress, sourceAddress, command)
+		checksum, _checksumErr := CrcCheck(destinationAddress, sourceAddress, command)
 		if _checksumErr != nil {
 			return nil, errors.Wrap(_checksumErr, "Error parsing 'checksum' field")
 		}
@@ -245,7 +245,7 @@ func (m *DF1SymbolMessageFrame) Serialize(writeBuffer utils.WriteBuffer) error {
 
 		// Checksum Field (checksum) (Calculated)
 		{
-			_checksum, _checksumErr := DF1UtilsCrcCheck(m.DestinationAddress, m.SourceAddress, m.Command)
+			_checksum, _checksumErr := CrcCheck(m.DestinationAddress, m.SourceAddress, m.Command)
 			if _checksumErr != nil {
 				return errors.Wrap(_checksumErr, "Error serializing 'checksum' field")
 			}
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/DF1UnprotectedReadResponse.go b/plc4go/internal/plc4go/df1/readwrite/model/DF1UnprotectedReadResponse.go
index 6f1e950..439e03f 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/DF1UnprotectedReadResponse.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/DF1UnprotectedReadResponse.go
@@ -91,7 +91,7 @@ func (m *DF1UnprotectedReadResponse) LengthInBitsConditional(lastItem bool) uint
 
 	// Manual Array Field (data)
 	data := m.Data
-	lengthInBits += DF1UtilsDataLength(data) * 8
+	lengthInBits += DataLength(data) * 8
 
 	return lengthInBits
 }
@@ -110,8 +110,8 @@ func DF1UnprotectedReadResponseParse(readBuffer utils.ReadBuffer) (*DF1Command,
 	// Manual Array Field (data)
 	// Terminated array
 	_dataList := make([]byte, 0)
-	for !((bool)(DF1UtilsDataTerminate(readBuffer))) {
-		_dataList = append(_dataList, ((byte)(DF1UtilsReadData(readBuffer))))
+	for !((bool)(DataTerminate(readBuffer))) {
+		_dataList = append(_dataList, ((byte)(ReadData(readBuffer))))
 
 	}
 	data := make([]byte, len(_dataList))
@@ -147,7 +147,7 @@ func (m *DF1UnprotectedReadResponse) Serialize(writeBuffer utils.WriteBuffer) er
 				return pushErr
 			}
 			for _, Element := range m.Data {
-				DF1UtilsWriteData(writeBuffer, Element)
+				WriteData(writeBuffer, Element)
 			}
 			if popErr := writeBuffer.PopContext("data", utils.WithRenderAsList(true)); popErr != nil {
 				return popErr
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper.go b/plc4go/internal/plc4go/df1/readwrite/model/StaticHelper.go
similarity index 88%
rename from plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper.go
rename to plc4go/internal/plc4go/df1/readwrite/model/StaticHelper.go
index 8e94eca..0482e2f 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/StaticHelper.go
@@ -31,7 +31,7 @@ func init() {
 	table = crc.NewTable(&crc.Parameters{Width: 16, Polynomial: 0x8005, Init: 0x0000, ReflectIn: true, ReflectOut: true, FinalXor: 0x0000})
 }
 
-func DF1UtilsCrcCheck(destinationAddress uint8, sourceAddress uint8, command *DF1Command) (uint16, error) {
+func CrcCheck(destinationAddress uint8, sourceAddress uint8, command *DF1Command) (uint16, error) {
 	df1Crc := table.InitCrc()
 	df1Crc = table.UpdateCrc(df1Crc, []byte{destinationAddress, sourceAddress})
 	bufferByteBased := utils.NewWriteBufferByteBased()
@@ -45,14 +45,14 @@ func DF1UtilsCrcCheck(destinationAddress uint8, sourceAddress uint8, command *DF
 	return table.CRC16(df1Crc), nil
 }
 
-func DF1UtilsDataTerminate(io utils.ReadBuffer) bool {
+func DataTerminate(io utils.ReadBuffer) bool {
 	rbbb := io.(utils.ReadBufferByteBased)
 	// The byte sequence 0x10 followed by 0x03 indicates the end of the message,
 	// so if we would read this, we abort the loop and stop reading data.
 	return rbbb.PeekByte(0) == 0x10 && rbbb.PeekByte(1) == 0x03
 }
 
-func DF1UtilsReadData(io utils.ReadBuffer) uint8 {
+func ReadData(io utils.ReadBuffer) uint8 {
 	rbbb := io.(utils.ReadBufferByteBased)
 	// If we read a 0x10, this has to be followed by another 0x10, which is how
 	// this value is escaped in DF1, so if we encounter two 0x10, we simply ignore the first.
@@ -63,7 +63,7 @@ func DF1UtilsReadData(io utils.ReadBuffer) uint8 {
 	return data
 }
 
-func DF1UtilsWriteData(io utils.WriteBuffer, element uint8) {
+func WriteData(io utils.WriteBuffer, element uint8) {
 	if element == 0x10 {
 		// If a value is 0x10, this has to be duplicated in order to be escaped.
 		io.WriteUint8("", 8, element)
@@ -71,7 +71,7 @@ func DF1UtilsWriteData(io utils.WriteBuffer, element uint8) {
 	io.WriteUint8("", 8, element)
 }
 
-func DF1UtilsDataLength(data []byte) uint16 {
+func DataLength(data []byte) uint16 {
 	length := uint16(0)
 	for _, datum := range data {
 		if datum == 0x10 {
diff --git a/plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper_test.go b/plc4go/internal/plc4go/df1/readwrite/model/StaticHelper_test.go
similarity index 94%
rename from plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper_test.go
rename to plc4go/internal/plc4go/df1/readwrite/model/StaticHelper_test.go
index 1eb4e56..1c7b434 100644
--- a/plc4go/internal/plc4go/df1/readwrite/model/Df1StaticHelper_test.go
+++ b/plc4go/internal/plc4go/df1/readwrite/model/StaticHelper_test.go
@@ -63,7 +63,7 @@ func TestDF1UtilsCrcCheck(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := DF1UtilsCrcCheck(tt.args.destinationAddress, tt.args.sourceAddress, tt.args.command)
+			got, err := CrcCheck(tt.args.destinationAddress, tt.args.sourceAddress, tt.args.command)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("DF1UtilsCrcCheck() error = %v, wantErr %v", err, tt.wantErr)
 				return
diff --git a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataStaticHelper.go b/plc4go/internal/plc4go/firmata/readwrite/model/StaticHelper.go
similarity index 82%
rename from plc4go/internal/plc4go/firmata/readwrite/model/FirmataStaticHelper.go
rename to plc4go/internal/plc4go/firmata/readwrite/model/StaticHelper.go
index 9117ba9..f22a9c0 100644
--- a/plc4go/internal/plc4go/firmata/readwrite/model/FirmataStaticHelper.go
+++ b/plc4go/internal/plc4go/firmata/readwrite/model/StaticHelper.go
@@ -21,11 +21,11 @@ package model
 
 import "github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
 
-func FirmataUtilsIsSysexEnd(io utils.ReadBuffer) bool {
+func IsSysexEnd(io utils.ReadBuffer) bool {
 	return io.(utils.ReadBufferByteBased).PeekByte(0) == 0xF7
 }
 
-func FirmataUtilsParseSysexString(io utils.ReadBuffer) int8 {
+func ParseSysexString(io utils.ReadBuffer) int8 {
 	aByte, err := io.ReadInt8("", 8)
 	if err != nil {
 		return 0
@@ -35,11 +35,11 @@ func FirmataUtilsParseSysexString(io utils.ReadBuffer) int8 {
 	return aByte
 }
 
-func FirmataUtilsSerializeSysexString(io utils.WriteBuffer, data byte) {
+func SerializeSysexString(io utils.WriteBuffer, data byte) {
 	_ = io.WriteByte("", data)
 	_ = io.WriteByte("", 0x00)
 }
 
-func FirmataUtilsLengthSysexString(data []byte) uint16 {
+func LengthSysexString(data []byte) uint16 {
 	return uint16(len(data) * 2)
 }
diff --git a/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommandReportFirmwareResponse.go b/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommandReportFirmwareResponse.go
index 1e5bd36..56f3192 100644
--- a/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommandReportFirmwareResponse.go
+++ b/plc4go/internal/plc4go/firmata/readwrite/model/SysexCommandReportFirmwareResponse.go
@@ -104,7 +104,7 @@ func (m *SysexCommandReportFirmwareResponse) LengthInBitsConditional(lastItem bo
 
 	// Manual Array Field (fileName)
 	fileName := m.FileName
-	lengthInBits += FirmataUtilsLengthSysexString(fileName) * 8
+	lengthInBits += LengthSysexString(fileName) * 8
 
 	return lengthInBits
 }
@@ -135,8 +135,8 @@ func SysexCommandReportFirmwareResponseParse(readBuffer utils.ReadBuffer, respon
 	// Manual Array Field (fileName)
 	// Terminated array
 	_fileNameList := make([]byte, 0)
-	for !((bool)(FirmataUtilsIsSysexEnd(readBuffer))) {
-		_fileNameList = append(_fileNameList, ((byte)(FirmataUtilsParseSysexString(readBuffer))))
+	for !((bool)(IsSysexEnd(readBuffer))) {
+		_fileNameList = append(_fileNameList, ((byte)(ParseSysexString(readBuffer))))
 
 	}
 	fileName := make([]byte, len(_fileNameList))
@@ -188,7 +188,7 @@ func (m *SysexCommandReportFirmwareResponse) Serialize(writeBuffer utils.WriteBu
 				return pushErr
 			}
 			for _, Element := range m.FileName {
-				FirmataUtilsSerializeSysexString(writeBuffer, Element)
+				SerializeSysexString(writeBuffer, Element)
 			}
 			if popErr := writeBuffer.PopContext("fileName", utils.WithRenderAsList(true)); popErr != nil {
 				return popErr
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/AssociatedValueType.go b/plc4go/internal/plc4go/s7/readwrite/model/AssociatedValueType.go
index d2cd6a6..daa7d92 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/AssociatedValueType.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/AssociatedValueType.go
@@ -123,7 +123,7 @@ func AssociatedValueTypeParse(readBuffer utils.ReadBuffer) (*AssociatedValueType
 	if pullErr := readBuffer.PullContext("valueLength"); pullErr != nil {
 		return nil, pullErr
 	}
-	valueLength, _valueLengthErr := S7EventHelperRightShift3(readBuffer)
+	valueLength, _valueLengthErr := RightShift3(readBuffer)
 	if _valueLengthErr != nil {
 		return nil, errors.Wrap(_valueLengthErr, "Error parsing 'valueLength' field")
 	}
@@ -136,8 +136,8 @@ func AssociatedValueTypeParse(readBuffer utils.ReadBuffer) (*AssociatedValueType
 		return nil, pullErr
 	}
 	// Count array
-	data := make([]uint8, S7EventHelperEventItemLength(readBuffer, valueLength))
-	for curItem := uint16(0); curItem < uint16(S7EventHelperEventItemLength(readBuffer, valueLength)); curItem++ {
+	data := make([]uint8, EventItemLength(readBuffer, valueLength))
+	for curItem := uint16(0); curItem < uint16(EventItemLength(readBuffer, valueLength)); curItem++ {
 		_item, _err := readBuffer.ReadUint8("", 8)
 		if _err != nil {
 			return nil, errors.Wrap(_err, "Error parsing 'data' field")
@@ -189,7 +189,7 @@ func (m *AssociatedValueType) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("transportSize"); pushErr != nil {
 		return pushErr
 	}
-	_valueLengthErr := S7EventHelperLeftShift3(writeBuffer, m.ValueLength)
+	_valueLengthErr := LeftShift3(writeBuffer, m.ValueLength)
 	if popErr := writeBuffer.PopContext("valueLength"); popErr != nil {
 		return popErr
 	}
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go b/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
index 8aab0b0..2de8a88 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
@@ -191,7 +191,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataProtocolId string, stringLen
 	case dataProtocolId == "IEC61131_CHAR": // CHAR
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseS7Char(readBuffer, "UTF-8")
+		value, _valueErr := ParseS7Char(readBuffer, "UTF-8")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -200,7 +200,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataProtocolId string, stringLen
 	case dataProtocolId == "IEC61131_WCHAR": // CHAR
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseS7Char(readBuffer, "UTF-16")
+		value, _valueErr := ParseS7Char(readBuffer, "UTF-16")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -209,7 +209,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataProtocolId string, stringLen
 	case dataProtocolId == "IEC61131_STRING": // STRING
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseS7String(readBuffer, stringLength, "UTF-8")
+		value, _valueErr := ParseS7String(readBuffer, stringLength, "UTF-8")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -218,7 +218,7 @@ func DataItemParse(readBuffer utils.ReadBuffer, dataProtocolId string, stringLen
 	case dataProtocolId == "IEC61131_WSTRING": // STRING
 
 		// Manual Field (value)
-		value, _valueErr := StaticHelperParseS7String(readBuffer, stringLength, "UTF-16")
+		value, _valueErr := ParseS7String(readBuffer, stringLength, "UTF-16")
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -430,28 +430,28 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, value api.PlcValue, dataPr
 	case dataProtocolId == "IEC61131_CHAR": // CHAR
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeS7Char(writeBuffer, value, "UTF-8")
+		_valueErr := SerializeS7Char(writeBuffer, value, "UTF-8")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
 	case dataProtocolId == "IEC61131_WCHAR": // CHAR
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeS7Char(writeBuffer, value, "UTF-16")
+		_valueErr := SerializeS7Char(writeBuffer, value, "UTF-16")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
 	case dataProtocolId == "IEC61131_STRING": // STRING
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeS7String(writeBuffer, value, stringLength, "UTF-8")
+		_valueErr := SerializeS7String(writeBuffer, value, stringLength, "UTF-8")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
 	case dataProtocolId == "IEC61131_WSTRING": // STRING
 
 		// Manual Field (value)
-		_valueErr := StaticHelperSerializeS7String(writeBuffer, value, stringLength, "UTF-16")
+		_valueErr := SerializeS7String(writeBuffer, value, stringLength, "UTF-16")
 		if _valueErr != nil {
 			return errors.Wrap(_valueErr, "Error serializing 'value' field")
 		}
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/DateAndTime.go b/plc4go/internal/plc4go/s7/readwrite/model/DateAndTime.go
index 61b4187..cacce1b 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/DateAndTime.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/DateAndTime.go
@@ -113,7 +113,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("year"); pullErr != nil {
 		return nil, pullErr
 	}
-	year, _yearErr := S7EventHelperBcdToInt(readBuffer)
+	year, _yearErr := BcdToInt(readBuffer)
 	if _yearErr != nil {
 		return nil, errors.Wrap(_yearErr, "Error parsing 'year' field")
 	}
@@ -125,7 +125,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("month"); pullErr != nil {
 		return nil, pullErr
 	}
-	month, _monthErr := S7EventHelperBcdToInt(readBuffer)
+	month, _monthErr := BcdToInt(readBuffer)
 	if _monthErr != nil {
 		return nil, errors.Wrap(_monthErr, "Error parsing 'month' field")
 	}
@@ -137,7 +137,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("day"); pullErr != nil {
 		return nil, pullErr
 	}
-	day, _dayErr := S7EventHelperBcdToInt(readBuffer)
+	day, _dayErr := BcdToInt(readBuffer)
 	if _dayErr != nil {
 		return nil, errors.Wrap(_dayErr, "Error parsing 'day' field")
 	}
@@ -149,7 +149,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("hour"); pullErr != nil {
 		return nil, pullErr
 	}
-	hour, _hourErr := S7EventHelperBcdToInt(readBuffer)
+	hour, _hourErr := BcdToInt(readBuffer)
 	if _hourErr != nil {
 		return nil, errors.Wrap(_hourErr, "Error parsing 'hour' field")
 	}
@@ -161,7 +161,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("minutes"); pullErr != nil {
 		return nil, pullErr
 	}
-	minutes, _minutesErr := S7EventHelperBcdToInt(readBuffer)
+	minutes, _minutesErr := BcdToInt(readBuffer)
 	if _minutesErr != nil {
 		return nil, errors.Wrap(_minutesErr, "Error parsing 'minutes' field")
 	}
@@ -173,7 +173,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("seconds"); pullErr != nil {
 		return nil, pullErr
 	}
-	seconds, _secondsErr := S7EventHelperBcdToInt(readBuffer)
+	seconds, _secondsErr := BcdToInt(readBuffer)
 	if _secondsErr != nil {
 		return nil, errors.Wrap(_secondsErr, "Error parsing 'seconds' field")
 	}
@@ -185,7 +185,7 @@ func DateAndTimeParse(readBuffer utils.ReadBuffer) (*DateAndTime, error) {
 	if pullErr := readBuffer.PullContext("msec"); pullErr != nil {
 		return nil, pullErr
 	}
-	msec, _msecErr := S7EventHelperS7msecToInt(readBuffer)
+	msec, _msecErr := S7msecToInt(readBuffer)
 	if _msecErr != nil {
 		return nil, errors.Wrap(_msecErr, "Error parsing 'msec' field")
 	}
@@ -216,7 +216,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_yearErr := S7EventHelperByteToBcd(writeBuffer, m.Year)
+	_yearErr := ByteToBcd(writeBuffer, m.Year)
 	if popErr := writeBuffer.PopContext("year"); popErr != nil {
 		return popErr
 	}
@@ -228,7 +228,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_monthErr := S7EventHelperByteToBcd(writeBuffer, m.Month)
+	_monthErr := ByteToBcd(writeBuffer, m.Month)
 	if popErr := writeBuffer.PopContext("month"); popErr != nil {
 		return popErr
 	}
@@ -240,7 +240,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_dayErr := S7EventHelperByteToBcd(writeBuffer, m.Day)
+	_dayErr := ByteToBcd(writeBuffer, m.Day)
 	if popErr := writeBuffer.PopContext("day"); popErr != nil {
 		return popErr
 	}
@@ -252,7 +252,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_hourErr := S7EventHelperByteToBcd(writeBuffer, m.Hour)
+	_hourErr := ByteToBcd(writeBuffer, m.Hour)
 	if popErr := writeBuffer.PopContext("hour"); popErr != nil {
 		return popErr
 	}
@@ -264,7 +264,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_minutesErr := S7EventHelperByteToBcd(writeBuffer, m.Minutes)
+	_minutesErr := ByteToBcd(writeBuffer, m.Minutes)
 	if popErr := writeBuffer.PopContext("minutes"); popErr != nil {
 		return popErr
 	}
@@ -276,7 +276,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_secondsErr := S7EventHelperByteToBcd(writeBuffer, m.Seconds)
+	_secondsErr := ByteToBcd(writeBuffer, m.Seconds)
 	if popErr := writeBuffer.PopContext("seconds"); popErr != nil {
 		return popErr
 	}
@@ -288,7 +288,7 @@ func (m *DateAndTime) Serialize(writeBuffer utils.WriteBuffer) error {
 	if pushErr := writeBuffer.PushContext("dow"); pushErr != nil {
 		return pushErr
 	}
-	_msecErr := S7EventHelperIntToS7msec(writeBuffer, m.Msec)
+	_msecErr := IntToS7msec(writeBuffer, m.Msec)
 	if popErr := writeBuffer.PopContext("msec"); popErr != nil {
 		return popErr
 	}
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7EventHelper.go b/plc4go/internal/plc4go/s7/readwrite/model/S7EventHelper.go
deleted file mode 100644
index 6c24c97..0000000
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7EventHelper.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package model
-
-import (
-	"github.com/apache/plc4x/plc4go/internal/plc4go/spi/utils"
-)
-
-func S7EventHelperRightShift3(readBuffer utils.ReadBuffer) (uint16, error) {
-	return 0, nil
-}
-
-func S7EventHelperLeftShift3(writeBuffer utils.WriteBuffer, valueLength uint16) error {
-	return nil
-}
-
-func S7EventHelperEventItemLength(readBuffer utils.ReadBuffer, valueLength uint16) uint16 {
-	return 0
-}
-
-func S7EventHelperBcdToInt(readBuffer utils.ReadBuffer) (uint8, error) {
-	return 0, nil
-}
-
-func S7EventHelperByteToBcd(writeBuffer utils.WriteBuffer, value uint8) error {
-	return nil
-}
-
-func S7EventHelperS7msecToInt(readBuffer utils.ReadBuffer) (uint16, error) {
-	return 0, nil
-}
-
-func S7EventHelperIntToS7msec(writeBuffer utils.WriteBuffer, value uint16) error {
-	return nil
-}
diff --git a/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go b/plc4go/internal/plc4go/s7/readwrite/model/StaticHelper.go
similarity index 66%
rename from plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go
rename to plc4go/internal/plc4go/s7/readwrite/model/StaticHelper.go
index 30a7bfc..225521c 100644
--- a/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go
+++ b/plc4go/internal/plc4go/s7/readwrite/model/StaticHelper.go
@@ -25,7 +25,7 @@ import (
 	"time"
 )
 
-func StaticHelperParseTiaTime(io utils.ReadBuffer) (uint32, error) {
+func ParseTiaTime(io utils.ReadBuffer) (uint32, error) {
 	/*try {
 	      int millisSinceMidnight = io.readInt(32);
 	      return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
@@ -36,12 +36,12 @@ func StaticHelperParseTiaTime(io utils.ReadBuffer) (uint32, error) {
 	return 0, nil
 }
 
-func StaticHelperSerializeTiaTime(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeTiaTime(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing TIME not implemented");
 	return nil
 }
 
-func StaticHelperParseS5Time(io utils.ReadBuffer) (uint32, error) {
+func ParseS5Time(io utils.ReadBuffer) (uint32, error) {
 	/*try {
 	      int stuff = io.readInt(16);
 	      // TODO: Implement this correctly.
@@ -52,22 +52,22 @@ func StaticHelperParseS5Time(io utils.ReadBuffer) (uint32, error) {
 	return 0, nil
 }
 
-func StaticHelperSerializeS5Time(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeS5Time(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing S5TIME not implemented");
 	return nil
 }
 
-func StaticHelperParseTiaLTime(io utils.ReadBuffer) (uint32, error) {
+func ParseTiaLTime(io utils.ReadBuffer) (uint32, error) {
 	//throw new NotImplementedException("LTIME not implemented");
 	return 0, nil
 }
 
-func StaticHelperSerializeTiaLTime(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeTiaLTime(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing LTIME not implemented");
 	return nil
 }
 
-func StaticHelperParseTiaTimeOfDay(io utils.ReadBuffer) (time.Time, error) {
+func ParseTiaTimeOfDay(io utils.ReadBuffer) (time.Time, error) {
 	/*try {
 	      long millisSinceMidnight = io.readUnsignedLong(32);
 	      return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
@@ -78,12 +78,12 @@ func StaticHelperParseTiaTimeOfDay(io utils.ReadBuffer) (time.Time, error) {
 	return time.Time{}, nil
 }
 
-func StaticHelperSerializeTiaTimeOfDay(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeTiaTimeOfDay(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing TIME_OF_DAY not implemented");
 	return nil
 }
 
-func StaticHelperParseTiaDate(io utils.ReadBuffer) (time.Time, error) {
+func ParseTiaDate(io utils.ReadBuffer) (time.Time, error) {
 	/*try {
 	      int daysSince1990 = io.readUnsignedInt(16);
 	      return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS);
@@ -93,12 +93,12 @@ func StaticHelperParseTiaDate(io utils.ReadBuffer) (time.Time, error) {
 	return time.Time{}, nil
 }
 
-func StaticHelperSerializeTiaDate(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeTiaDate(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing DATE not implemented");
 	return nil
 }
 
-func StaticHelperParseTiaDateTime(io utils.ReadBuffer) (time.Time, error) {
+func ParseTiaDateTime(io utils.ReadBuffer) (time.Time, error) {
 	/*try {
 	      int year = io.readUnsignedInt(16);
 	      int month = io.readUnsignedInt(8);
@@ -117,37 +117,65 @@ func StaticHelperParseTiaDateTime(io utils.ReadBuffer) (time.Time, error) {
 	return time.Time{}, nil
 }
 
-func StaticHelperSerializeTiaDateTime(io utils.WriteBuffer, value values.PlcValue) error {
+func SerializeTiaDateTime(io utils.WriteBuffer, value values.PlcValue) error {
 	//throw new NotImplementedException("Serializing DATE_AND_TIME not implemented");
 	return nil
 }
 
-func StaticHelperParseS7String(io utils.ReadBuffer, stringLength int32, encoding string) (string, error) {
+func ParseS7String(io utils.ReadBuffer, stringLength int32, encoding string) (string, error) {
 	var multiplier int32
 	switch encoding {
 	case "UTF-8":
-		multiplier = 0
+		multiplier = 8
 	case "UTF-16":
 		multiplier = 16
 	}
 	return io.ReadString("", uint32(stringLength*multiplier))
 }
 
-func StaticHelperSerializeS7String(io utils.WriteBuffer, value values.PlcValue, stringLength int32, encoding string) error {
+func SerializeS7String(io utils.WriteBuffer, value values.PlcValue, stringLength int32, encoding string) error {
 	var multiplier int32
 	switch encoding {
 	case "UTF-8":
-		multiplier = 0
+		multiplier = 8
 	case "UTF-16":
 		multiplier = 16
 	}
 	return io.WriteString("", uint32(stringLength*multiplier), encoding, value.GetString())
 }
 
-func StaticHelperParseS7Char(io utils.ReadBuffer, encoding string) (uint8, error) {
+func ParseS7Char(io utils.ReadBuffer, encoding string) (uint8, error) {
 	return io.ReadUint8("", 8)
 }
 
-func StaticHelperSerializeS7Char(io utils.WriteBuffer, value values.PlcValue, encoding string) error {
+func SerializeS7Char(io utils.WriteBuffer, value values.PlcValue, encoding string) error {
 	return io.WriteUint8("", 8, value.GetUint8())
 }
+
+func RightShift3(readBuffer utils.ReadBuffer) (uint16, error) {
+	return 0, nil
+}
+
+func LeftShift3(writeBuffer utils.WriteBuffer, valueLength uint16) error {
+	return nil
+}
+
+func EventItemLength(readBuffer utils.ReadBuffer, valueLength uint16) uint16 {
+	return 0
+}
+
+func BcdToInt(readBuffer utils.ReadBuffer) (uint8, error) {
+	return 0, nil
+}
+
+func ByteToBcd(writeBuffer utils.WriteBuffer, value uint8) error {
+	return nil
+}
+
+func S7msecToInt(readBuffer utils.ReadBuffer) (uint16, error) {
+	return 0, nil
+}
+
+func IntToS7msec(writeBuffer utils.WriteBuffer, value uint16) error {
+	return nil
+}
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/readwrite/utils/StaticHelper.java
similarity index 98%
rename from plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/utils/StaticHelper.java
rename to plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java
index c94a55a..afbed6c 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/readwrite/utils/StaticHelper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.ads.utils;
+package org.apache.plc4x.java.ads.readwrite.utils;
 
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.value.PlcValue;
diff --git a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/helper/CANOpenHelper.java b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
similarity index 96%
rename from plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/helper/CANOpenHelper.java
rename to plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
index 0312d32..566ac4b 100644
--- a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/helper/CANOpenHelper.java
+++ b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.canopen.helper;
+package org.apache.plc4x.java.canopen.readwrite.utils;
 
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.canopen.readwrite.SDOInitiateExpeditedUploadResponse;
@@ -29,7 +29,7 @@ import org.apache.plc4x.java.spi.generation.WriteBuffer;
 
 import static org.apache.plc4x.java.spi.generation.StaticHelper.COUNT;
 
-public class CANOpenHelper {
+public class StaticHelper {
 
     public static CANOpenService serviceId(short identifier) {
         return CANOpenService.enumForValue((byte) (identifier >> 7));
diff --git a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/transport/CANOpenFrameDataHandler.java b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/transport/CANOpenFrameDataHandler.java
index 9026793..9b0af9e 100644
--- a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/transport/CANOpenFrameDataHandler.java
+++ b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/transport/CANOpenFrameDataHandler.java
@@ -20,7 +20,7 @@ package org.apache.plc4x.java.canopen.transport;
 
 import java.util.function.Supplier;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.canopen.helper.CANOpenHelper;
+import org.apache.plc4x.java.canopen.readwrite.utils.StaticHelper;
 import org.apache.plc4x.java.canopen.readwrite.CANOpenFrame;
 import org.apache.plc4x.java.canopen.readwrite.CANOpenPayload;
 import org.apache.plc4x.java.canopen.readwrite.CANOpenService;
@@ -47,7 +47,7 @@ public class CANOpenFrameDataHandler implements FrameHandler<Message, CANOpenFra
 
     @Override
     public CANOpenFrame fromCAN(FrameData frame) {
-        CANOpenService service = CANOpenHelper.serviceId((short) frame.getNodeId());
+        CANOpenService service = StaticHelper.serviceId((short) frame.getNodeId());
         int nodeId = Math.abs(service.getMin() - frame.getNodeId());
         return new CANOpenFrame((short) nodeId, service, frame.read(new CANOpenPayloadIO(), service));
     }
diff --git a/plc4j/drivers/canopen/src/test/java/org/apache/plc4x/java/canopen/transport/IdentityCANOpenFrameBuilder.java b/plc4j/drivers/canopen/src/test/java/org/apache/plc4x/java/canopen/transport/IdentityCANOpenFrameBuilder.java
index 41b76ed..e68329f 100644
--- a/plc4j/drivers/canopen/src/test/java/org/apache/plc4x/java/canopen/transport/IdentityCANOpenFrameBuilder.java
+++ b/plc4j/drivers/canopen/src/test/java/org/apache/plc4x/java/canopen/transport/IdentityCANOpenFrameBuilder.java
@@ -19,7 +19,7 @@ under the License.
 package org.apache.plc4x.java.canopen.transport;
 
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.canopen.helper.CANOpenHelper;
+import org.apache.plc4x.java.canopen.readwrite.utils.StaticHelper;
 import org.apache.plc4x.java.canopen.readwrite.CANOpenFrame;
 import org.apache.plc4x.java.canopen.readwrite.CANOpenService;
 import org.apache.plc4x.java.canopen.readwrite.io.CANOpenPayloadIO;
@@ -41,7 +41,7 @@ public class IdentityCANOpenFrameBuilder implements CANFrameBuilder<CANOpenFrame
 
     @Override
     public CANFrameBuilder<CANOpenFrame> withId(int nodeId) {
-        this.service = CANOpenHelper.serviceId((short) nodeId);
+        this.service = StaticHelper.serviceId((short) nodeId);
         this.nodeId = (short) Math.abs(service.getMin() - nodeId);
         return this;
     }
diff --git a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/FirmataUtils.java b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/StaticHelper.java
similarity index 98%
rename from plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/FirmataUtils.java
rename to plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/StaticHelper.java
index b1bff30..a040013 100644
--- a/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/FirmataUtils.java
+++ b/plc4j/drivers/firmata/src/main/java/org/apache/plc4x/java/firmata/readwrite/utils/StaticHelper.java
@@ -23,7 +23,7 @@ import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
 import org.apache.plc4x.java.spi.generation.WriteBuffer;
 
-public class FirmataUtils {
+public class StaticHelper {
 
     public static boolean isSysexEnd(ReadBuffer io) {
         return ((ReadBufferByteBased) io).getBytes(io.getPos(), io.getPos() + 1)[0] == (byte) 0xF7;
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
similarity index 95%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
index 402b9dc..c324907 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/readwrite/utils/StaticHelper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.profinet.utils;
+package org.apache.plc4x.java.profinet.readwrite.utils;
 
 public class StaticHelper {
 
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
new file mode 100644
index 0000000..d5de172
--- /dev/null
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
@@ -0,0 +1,2052 @@
+/*
+ * 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.s7.readwrite.utils;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.s7.events.S7AlarmEvent;
+import org.apache.plc4x.java.s7.events.S7ModeEvent;
+import org.apache.plc4x.java.s7.events.S7SysEvent;
+import org.apache.plc4x.java.s7.readwrite.DataTransportErrorCode;
+import org.apache.plc4x.java.s7.readwrite.ModeTransitionType;
+import org.apache.plc4x.java.s7.utils.S7DiagnosticEventId;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1|
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * \__________/\__________/\____________________/
+ * Module      Number of   Number of the partial
+ * class       the partial list
+ * list
+ * extract
+ *
+ * <b>Module Class:</b>
+ * +--------------+-----------------+
+ * | Module class | Coding (Binary) |
+ * +--------------|-----------------+
+ * |     CPU      |      0000       |
+ * +--------------|-----------------+
+ * |     IM       |      0100       |
+ * +--------------|-----------------+
+ * |     FM       |      1000       |
+ * +--------------|-----------------+
+ * |     CP       |      1100       |
+ * +--------------|-----------------+
+ *
+ * <b>Possible SSL Partial Lists:</b>
+ * +-----------------------------------------------------------|--------------+
+ * | Module class                                              |    SSL-ID    |
+ * +-----------------------------------------------------------|--------------+
+ * | Module identification                                     |    16#xy11   |
+ * +-----------------------------------------------------------|--------------+
+ * | CPU characteristics                                       |    16#xy12   |
+ * +-----------------------------------------------------------|--------------+
+ * | User memory areas                                         |    16#xy13   |
+ * +-----------------------------------------------------------|--------------+
+ * | System areas                                              |    16#xy14   |
+ * +-----------------------------------------------------------|--------------+
+ * | Block types                                               |    16#xy15   |
+ * +-----------------------------------------------------------|--------------+
+ * | Interrupt status                                          |    16#xy22   |
+ * +-----------------------------------------------------------|--------------+
+ * | Assignment between process image partitions and OBs       |    16#xy25   |
+ * +-----------------------------------------------------------|--------------+
+ * | Communication status data                                 |    16#xy32   |
+ * +-----------------------------------------------------------|--------------+
+ * | H CPU group information                                   |    16#xy71   |
+ * +-----------------------------------------------------------|--------------+
+ * | Status of the module LEDs                                 |    16#xy74   |
+ * +-----------------------------------------------------------|--------------+
+ * | Switched DP slaves in the H-system                        |    16#xy75   |
+ * +-----------------------------------------------------------|--------------+
+ * | Module status information                                 |    16#xy91   |
+ * +-----------------------------------------------------------|--------------+
+ * | Rack / station status information                         |    16#xy92   |
+ * +-----------------------------------------------------------|--------------+
+ * | Rack / station status information                         |    16#xy94   |
+ * +-----------------------------------------------------------|--------------+
+ * | Extended DP master system / PROFINET IO system information|    16#xy95   |
+ * +-----------------------------------------------------------|--------------+
+ * | Module status information, PROFINET IO and PROFIBUS DP    |    16#xy96   |
+ * +-----------------------------------------------------------|--------------+
+ * | Tool changer information (PROFINET IO)                    |    16#xy9C   |
+ * +-----------------------------------------------------------|--------------+
+ * | Diagnostic buffer of the CPU                              |    16#xyA0   |
+ * +-----------------------------------------------------------|--------------+
+ * | Module diagnostic information (data record 0)             |    16#xyB1   |
+ * +-----------------------------------------------------------|--------------+
+ * | Module diagnostic information (data record 1),            |    16#xyB2   |
+ * | geographical address                                      |              |
+ * +-----------------------------------------------------------|--------------+
+ * | Module diagnostic information (data record 1),            |    16#xyB3   |
+ * | logical address                                           |              |
+ * +-----------------------------------------------------------|--------------+
+ * | Diagnostic data of a DP slave                             |    16#xyB4   |
+ * +-----------------------------------------------------------|--------------+
+ */
+
+public class StaticHelper {
+
+    public enum OB {
+        FREE_CYC(0X0000, "OB1 Free cycle"),
+
+        //Time of day
+        TOD_INT0(0X000A, "OB10 Time of day interrupt"),
+        TOD_INT1(0X000B, "OB11 Time of day interrupt"),
+        TOD_INT2(0X000C, "OB12 Time of day interrupt"),
+        TOD_INT3(0X000D, "OB13 Time of day interrupt"),
+        TOD_INT4(0X000E, "OB14 Time of day interrupt"),
+        TOD_INT5(0X000F, "OB15 Time of day interrupt"),
+        TOD_INT6(0X0010, "OB16 Time of day interrupt"),
+        TOD_INT7(0X0011, "OB17 Time of day interrupt"),
+
+        //Time delay
+        DEL_INT0(0X0014, "OB20 Time delay interrupt"),
+        DEL_INT1(0X0015, "OB21 Time delay interrupt"),
+        DEL_INT2(0X0016, "OB22 Time delay interrupt"),
+        DEL_INT3(0X0017, "OB23 Time delay interrupt"),
+
+        //Cyclic
+        CYC_INT0(0X001E, "OB30 Cyclic interrupt"),
+        CYC_INT1(0X001F, "OB31 Cyclic interrupt"),
+        CYC_INT2(0X0020, "OB32 Cyclic interrupt"),
+        CYC_INT3(0X0021, "OB33 Cyclic interrupt"),
+        CYC_INT4(0X0022, "OB34 Cyclic interrupt"),
+        CYC_INT5(0X0023, "OB35 Cyclic interrupt"),
+        CYC_INT6(0X0024, "OB36 Cyclic interrupt"),
+        CYC_INT7(0X0025, "OB37 Cyclic interrupt"),
+        CYC_INT8(0X0026, "OB38 Cyclic interrupt"),
+
+        //Hardware interrupts
+        HW_INT0(0X0028, "OB40 Hardware interrupt"),
+        HW_INT1(0X0029, "OB41 Hardware interrupt"),
+        HW_INT2(0X002A, "OB42 Hardware interrupt"),
+        HW_INT3(0X002B, "OB43 Hardware interrupt"),
+        HW_INT4(0X002C, "OB44 Hardware interrupt"),
+        HW_INT5(0X002D, "OB45 Hardware interrupt"),
+        HW_INT6(0X002E, "OB46 Hardware interrupt"),
+        HW_INT7(0X002F, "OB47 Hardware interrupt"),
+
+        //Startup
+        BACKGROUND(0X005A, "OB90 Background"),
+        COMPLETE_RESTART(0X0064, "OB100 Startup"),
+        RESTART(0X0064, "OB101 Background"),
+        COLD_RESTART(0X005A, "OB101 Background"),
+
+        //Fault interrupts
+        CYC_FLT(0X0051, "OB80 Time execution error interrupt"),
+        PS_FLT(0X0051, "OB81 Power supply interrupt"),
+        IO_FLT1(0X0052, "OB82 Module diagnostic interrupt"),
+        IO_FLT2(0X0053, "OB83 Module change interrupt"),
+        CPU_FLT(0X0054, "OB84 CPU hardware error interrupt"),
+        OBNL_FLT(0X0055, "OB85 Program execution error interrupt"),
+        RACK_FLT(0X0056, "OB86 Rack fault interrupt"),
+        COMM_FLT(0X0057, "OB87 Communication error interrupt"),
+        BREAKUP_ERR(0X0058, "OB88 Process interrupt"),
+        SYNC_ERR(0X0079, "OB120 Synchronous error interrupt"),
+        PROG_ERR(0X0079, "OB121 Program error interrupt"),
+        MOD_ERR(0X007A, "OB122 Module error interrupt");
+
+        private final int code;
+        private final String description;
+
+        private static final Map<Integer, OB> map;
+
+        static {
+            map = new HashMap<>();
+            for (OB obid : OB.values()) {
+                map.put(obid.code, obid);
+            }
+        }
+
+        OB(final int code, final String description) {
+            this.code = code;
+            this.description = description;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public static OB valueOf(int code) {
+            return map.get(code);
+        }
+
+
+    }
+
+
+    public enum MODULE {
+        CPU(0X00),
+        IM(0X04),
+        FM(0X80),
+        CP(0XC0);
+
+        private final int code;
+
+        MODULE(final int code) {
+            this.code = code;
+        }
+
+        public int getCode() {
+            return code;
+        }
+    }
+
+    public enum LED_ID {
+        SF(0X0001, "Group error"),
+        INTF(0X0002, "Internal error"),
+        EXTF(0X0003, "External error"),
+        RUN(0X0004, "RUN"),
+        STOP(0X0005, "STOP"),
+        FRCE(0X0006, "Force"),
+        CRST(0X0007, "Cold restart"),
+        BAF(0X0008, "Battery fault"),
+        USR(0X0009, "User defined"),
+        USR1(0X000A, "User defined"),
+        BUS1F(0X000B, "Bus error interface 1"),
+        BUS2F(0X000C, "Bus error interface 2"),
+        REDF(0X000D, "Redundancy error"),
+        MSTR(0X000E, "Master"),
+        RACK0(0X000F, "Rack number 0"),
+        RACK1(0X0010, "Rack number 1"),
+        RACK2(0X0011, "Rack number 2"),
+        IFM1F(0X0012, "Interface error interface module 1"),
+        IFM2F(0X0013, "Interface error interface module 2"),
+        BUS3F(0X0014, "Bus error interface 3"),
+        MAINT(0X0015, "Maintenance demand"),
+        DC24V(0X0016, "DC24V"),
+        BUS5F(0X0017, "Bus error interface 5"),
+        BUS8F(0X0018, "Bus error interface 8"),
+        IF(0X0080, "Init failure"),
+        UF(0X0081, "User failure"),
+        MF(0X0082, "Monitoring failure"),
+        CF(0X0083, "Communication failure"),
+        TF(0X0084, "Task failure"),
+        APPL_STATE_RED(0X00EC, "APPL_STATE_RED"),
+        APPL_STATE_GREEN(0X00ED, "APPL_STATE_GREEN");
+
+        private final int code;
+        private final String description;
+
+        private static final Map<Integer, LED_ID> map;
+
+        static {
+            map = new HashMap<>();
+            for (LED_ID ledid : LED_ID.values()) {
+                map.put(ledid.code, ledid);
+            }
+        }
+
+        LED_ID(final int code, final String description) {
+            this.code = code;
+            this.description = description;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public static LED_ID valueOf(int code) {
+            return map.get(code);
+        }
+
+
+    }
+
+    /**
+     *
+     */
+    public enum CPU_CHARACTERISTICS {
+        CH_0x0000(0X0000, "MC7 processing unit (group with index 0000)"),
+        CH_0x0001(0X0001, "MC7 processing generating code"),
+        CH_0x0002(0X0002, "MC7 interpreter"),
+
+        CH_0x0100(0X0100, "Time system (group with index 0100)"),
+        CH_0x0101(0X0101, "1 ms resolution"),
+        CH_0x0102(0X0102, "10 ms resolution"),
+        CH_0x0103(0X0103, "No real time clock"),
+        CH_0x0104(0X0104, "BCD time-of-day format"),
+        CH_0x0105(0X0105, "All time-of-day functions"),
+        CH_0x0106(0X0106, "SFC 78 \"OB_RT\" is available"),
+
+        CH_0x0200(0X0200, "System response (group with index 0200)"),
+        CH_0x0201(0X0201, "Capable of multiprocessor mode"),
+        CH_0x0202(0X0202, "Cold restart, warm restart and hot restart possible"),
+        CH_0x0203(0X0203, "Cold restart and hot restart possible"),
+        CH_0x0204(0X0204, "Warm restart and hot restart possible"),
+        CH_0x0205(0X0205, "Only warm restart possible"),
+        CH_0x0206(0X0206, "New distributed I/O configuration is possible during\n" +
+            "RUN by using predefined resources"),
+        CH_0x0207(0X0207, "H-CPU in stand-alone mode: New distributed I/O configuration\n" +
+            "is possible during RUN by using predefined resources"),
+        CH_0x0208(0X0208, "For taking motion control functionality into account"),
+
+        CH_0x0300(0X0300, "MC7 Language description of the CPU (group with index 0300)"),
+        CH_0x0301(0X0301, "Reserved"),
+        CH_0x0302(0X0302, "All 32 bit fixed-point instructions"),
+        CH_0x0303(0X0303, "All floating-point instructions"),
+        CH_0x0304(0X0304, "sin, asin, cos, acos, tan, atan, sqr, sqrt, ln, exp"),
+        CH_0x0305(0X0305, "Accumulator 3/accumulator 4 with corresponding instructions\n" +
+            "(ENT,PUSH,POP,LEAVE)"),
+        CH_0x0306(0X0306, "Master Control Relay instructions"),
+        CH_0x0307(0X0307, "Address register 1 exists with corresponding instructions"),
+        CH_0x0308(0X0308, "Address register 2 exists with corresponding instructions"),
+        CH_0x0309(0X0309, "Operations for area-crossing addressing"),
+        CH_0x030A(0X030A, "Operations for area-internal addressing"),
+        CH_0x030B(0X030B, "All memory-indirect addressing instructions for bit memory (M)"),
+        CH_0x030C(0X030C, "All memory-indirect addressing instructions for data blocks (DB)"),
+        CH_0x030D(0X030D, "All memory-indirect addressing instructions for data blocks (DI)"),
+        CH_0x030E(0X030E, "All memory-indirect addressing instructions for local data (L)"),
+        CH_0x030F(0X030F, "All instructions for parameter transfer in FCs"),
+        CH_0x0310(0X0310, "Memory bit edge instructions for process image input (I)"),
+        CH_0x0311(0X0311, "Memory bit edge instructions for process image output (Q)"),
+        CH_0x0312(0X0312, "Memory bit edge instructions for bit memory (M)"),
+        CH_0x0313(0X0313, "Memory bit edge instructions for data blocks (DB)"),
+        CH_0x0314(0X0314, "Memory bit edge instructions for data blocks (DI)"),
+        CH_0x0315(0X0315, "Memory bit edge instructions for local data (L)"),
+        CH_0x0316(0X0316, "Dynamic evaluation of the FC bit"),
+        CH_0x0317(0X0317, "Dynamic local data area with the corresponding instructions"),
+        CH_0x0318(0X0318, "Reserved"),
+        CH_0x0319(0X0319, "Reserved"),
+
+        CH_0x0401(0X0401, "SFC 87 \"C_DIAG\" is available"),
+        CH_0x0402(0X0402, "SFC 88 \"C_CNTRL\" is available)");
+
+        private final int code;
+        private final String description;
+
+        private static final Map<Integer, CPU_CHARACTERISTICS> map;
+
+        static {
+            map = new HashMap<>();
+            for (CPU_CHARACTERISTICS cpuc : CPU_CHARACTERISTICS.values()) {
+                map.put(cpuc.code, cpuc);
+            }
+        }
+
+        CPU_CHARACTERISTICS(final int code, final String description) {
+            this.code = code;
+            this.description = description;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public static CPU_CHARACTERISTICS valueOf(int code) {
+            return map.get(code);
+        }
+
+
+    }
+
+    /**
+     *
+     */
+    public enum SSL {
+        ID_0x0011(0x0011, "Module identification.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY11(data);
+            }
+
+        },
+        ID_0x0012(0x0012, "CPU characteristics .") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY12(data);
+            }
+
+        },
+        ID_0x0013(0x0013, "User memory areas.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY13(data);
+            }
+
+        },
+        ID_0x0014(0x0014, "System areas.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY14(data);
+            }
+
+        },
+        ID_0x0015(0x0015, "Block types.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY15(data);
+            }
+
+        },
+        ID_0x001C(0x001C, "Component identification.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY1C(data);
+            }
+
+        },
+        ID_0x0022(0x0022, "Interrupt status.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY22(data);
+            }
+
+        },
+        ID_0x0025(0x0025, "Assignment between process image partitions and OBs.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY25(data);
+            }
+
+        },
+        ID_0x0032(0x0032, "Communication status data.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY32(data);
+            }
+
+        },
+        ID_0x0071(0x0071, "H CPU group information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY71(data);
+            }
+
+        },
+        ID_0x0074(0x0074, "Status of the module LEDs.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY74(data);
+            }
+
+        },
+        ID_0x0075(0x0075, "Switched DP slaves in the H-system.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY75(data);
+            }
+
+        },
+        ID_0x0090(0x0090, "DP Master System Information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY90(data);
+            }
+
+        },
+        ID_0x0091(0x0091, "Module status information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY91(data);
+            }
+
+        },
+        ID_0x0092(0x0092, "Rack / station status information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY92(data);
+            }
+
+        },
+        ID_0x0094(0x0094, "Rack / station status information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY94(data);
+            }
+
+        },
+        ID_0x0095(0x0095, "Extended DP master system / PROFINET IO system information.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY95(data);
+            }
+
+        },
+        ID_0x0096(0x0096, "Module status information, PROFINET IO and PROFIBUS DP.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY96(data);
+            }
+
+        },
+        ID_0x009C(0x009C, "Tool changer information (PROFINET IO).") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXY9C(data);
+            }
+
+        },
+        ID_0x00A0(0x00A0, "Diagnostic buffer of the CPU.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXYA0(data);
+            }
+
+        },
+        ID_0x00B1(0x00B1, "Module diagnostic information (data record 0) .") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXYB1(data);
+            }
+
+        },
+        ID_0x00B2(0x00B2, "Module diagnostic information (data record 1),geographical address.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXYB2(data);
+            }
+
+        },
+        ID_0x00B3(0x00B3, "Module diagnostic information (data record 1),logical address.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXYB3(data);
+            }
+
+        },
+        ID_0x00B4(0x00B4, "Diagnostic data of a DP slave.") {
+            @Override
+            public StringBuilder execute(ByteBuf data) {
+                return ID_0xXYB4(data);
+            }
+
+        };
+
+        private final int code;
+        private final String description;
+
+        private static final Map<Integer, SSL> map;
+
+        static {
+            map = new HashMap<>();
+            for (SSL subssl : SSL.values()) {
+                map.put(subssl.code, subssl);
+            }
+        }
+
+        SSL(final int code, final String description) {
+            this.code = code;
+            this.description = description;
+        }
+
+        public int getCode() {
+            return code;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public static SSL valueOf(int code) {
+            return map.get(code);
+        }
+
+        public abstract StringBuilder execute(ByteBuf data);
+
+        private static StringBuilder ID_0xXY11(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+
+                    sb.append("Index: ").append(data.readShort()).append("\r\n");
+                    byte[] bytestr = new byte[20];
+                    data.readBytes(bytestr, 0, 20);
+                    sb.append("Mlfb (Order number): ").append(new String(bytestr)).append("\r\n");
+                    sb.append("BGTyp (Moduler type ID): ").append(data.readShort()).append("\r\n");
+                    sb.append("Ausbg (Version of the module/hardware version): ").append(data.readShort()).append("\r\n");
+                    sb.append("Ausbe (Firmware version): ").append(data.readShort()).append("\r\n");
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY12(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    int code = data.readShort();
+                    sb.append(CPU_CHARACTERISTICS.valueOf(code)).append(": ").
+                        append(CPU_CHARACTERISTICS.valueOf(code).getDescription()).append("\r\n");
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY13(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    sb.append("Index: ").append(data.readShort()).append("\r\n");
+                    int code = data.readShort();
+                    int size = data.readInt();
+                    int mode = data.readShort();
+                    int granu = data.readShort();
+                    int ber1 = data.readInt();
+                    int be1egt1 = data.readInt();
+                    int block1 = data.readInt();
+                    int ber2 = data.readInt();
+                    int be1egt2 = data.readInt();
+                    int block2 = data.readInt();
+
+                    switch (code) {
+                        case 0x0001:
+                            sb.append("Code (Memory Type): ").append("Volatile memory (RAM)\r\n");
+                            break;
+                        case 0x0002:
+                            sb.append("Code (Memory Type): ").append("Non-volatile memory (FEPROM)\r\n");
+                            break;
+                        case 0x0003:
+                            sb.append("Code (Memory Type): ").append("mixed memory (RAM + FEPROM)\r\n");
+                            break;
+                    }
+                    sb.append("Size (Total size of the selected memory (total of area 1 and area 2)): ").append(size).append("\r\n");
+
+                    sb.append("Mode (Volatile memory area): ").append(((mode & 0x0001) != 0)).append("\r\n");
+                    sb.append("Mode (Non-volatile memory area): ").append(((mode & 0x0002) != 0)).append("\r\n");
+                    sb.append("Mode (Mixed memory area): ").append(((mode & 0x0004) != 0)).append("\r\n");
+                    sb.append("Mode (Code and data separate): ").append(((mode & 0x0008) != 0)).append("\r\n");
+                    sb.append("Mode (Code and data together): ").append(((mode & 0x0010) != 0)).append("\r\n");
+
+                    sb.append("Granu (Always zero): ").append(granu).append("\r\n");
+
+                    sb.append("Ber1 (Size of the volatile memory area in bytes): ").append(ber1).append("\r\n");
+                    sb.append("Belegt1 (Size of the volatile memory area being used): ").append(be1egt1).append("\r\n");
+                    sb.append("Block1 (Largest free block in the volatile memory area): ").append(block1).append("\r\n");
+
+                    sb.append("Ber2 (Size of the non-volatile memory area in bytes): ").append(ber2).append("\r\n");
+                    sb.append("Belegt2 (Size of the non-volatile memory area being used): ").append(be1egt2).append("\r\n");
+                    sb.append("Block2 (Largest free block in the non-volatile memory area): ").append(block2).append("\r\n");
+
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY14(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                for (int i = 1; i <= ssl_count; i++) {
+                    int index = data.readShort();
+                    int code = data.readShort();
+                    int quantity = data.readShort();
+                    int reman = data.readShort();
+
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    sb.append("Index: ").append(index).append(" System area: ");
+                    switch (index) {
+                        case 0x0001:
+                            sb.append("PII (number in bytes)").append("\r\n");
+                            break;
+                        case 0x0002:
+                            sb.append("PIQ (number in bytes))").append("\r\n");
+                            break;
+                        case 0x0003:
+                            sb.append("memory (number in bits)").append("\r\n");
+                            break;
+                        case 0x0004:
+                            sb.append("timers (number)").append("\r\n");
+                            break;
+                        case 0x0005:
+                            sb.append("counter (number)").append("\r\n");
+                            break;
+                        case 0x0006:
+                            sb.append("number of bytes in the logical address area)").append("\r\n");
+                            break;
+                        case 0x0007:
+                            sb.append("local data (entire local data area of the CPU in bytes)").append("\r\n");
+                            break;
+                        case 0x0008:
+                            sb.append("memory (number in bytes)").append("\r\n");
+                            break;
+                        case 0x0009:
+                            sb.append("local data (entire local data area of the CPU in Kbytes)").append("\r\n");
+                            break;
+                    }
+                    sb.append("Code: ").append(code).append(" Memory type: ");
+                    switch (code) {
+                        case 0x0001:
+                            sb.append("volatile memory (RAM)").append("\r\n");
+                            break;
+                        case 0x0002:
+                            sb.append("non-volatile memory (FEPROM)").append("\r\n");
+                            break;
+                        case 0x0003:
+                            sb.append("mixed memory (RAM and FEPROM)").append("\r\n");
+                            break;
+                    }
+                    sb.append("Quantity: ").append(quantity).append("\r\n");
+                    sb.append("Reman: ").append(reman).append("\r\n");
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY15(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    int type = data.readShort();
+                    switch (type) {
+                        case 0x0800:
+                            sb.append("Block type: OB\r\n");
+                            break;
+                        case 0x0A00:
+                            sb.append("Block type: DB\r\n");
+                            break;
+                        case 0x0B00:
+                            sb.append("Block type: SDB\r\n");
+                            break;
+                        case 0x0C00:
+                            sb.append("Block type: FC\r\n");
+                            break;
+                        case 0x0E00:
+                            sb.append("Block type: FB\r\n");
+                            break;
+                        default:
+                    }
+                    sb.append("Maximum number of blocks of the type: ").append(data.readShort()).append("\r\n");
+                    sb.append("Maximum total size of the object to be loaded in Kbytes: ").append(data.readShort()).append("\r\n");
+                    sb.append("Maximum length of the work memory part of a block in bytes: ").append(data.readInt()).append("\r\n");
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY1C(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    int index = data.getShort(data.readerIndex());
+                    int index_b0 = data.readByte();
+                    int index_b1 = data.readByte();
+                    sb.append("Index: ").append(index).append("\r\n");
+                    sb.append("Index b1: ").append(index_b1).append("\r\n");
+
+                    switch (index_b1) {
+                        case 0x01:
+                        case 0x02: {
+                            byte[] strbyte = new byte[24];
+                            data.readBytes(strbyte, 0, 24);
+                            sb.append("Name: ").append(new String(strbyte)).append("\r\n");
+                            ByteBuf data2 = data.readSlice(8);
+                            sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        ;
+                        break;
+                        case 0x03: {
+                            byte[] strbyte = new byte[32];
+                            data.readBytes(strbyte, 0, 32);
+                            sb.append("Tag: ").append(new String(strbyte)).append("\r\n");
+                        }
+                        break;
+                        case 0x04: {
+                            byte[] strbyte = new byte[26];
+                            data.readBytes(strbyte, 0, 26);
+                            sb.append("Copyright: ").append(new String(strbyte)).append("\r\n");
+                            ByteBuf data2 = data.readSlice(6);
+                            sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                        case 0x05: {
+                            byte[] strbyte = new byte[24];
+                            data.readBytes(strbyte, 0, 24);
+                            sb.append("Serial: ").append(new String(strbyte)).append("\r\n");
+                            ByteBuf data2 = data.readSlice(8);
+                            sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                        case 0x06: {
+
+                        }
+                        break;
+                        case 0x07: {
+                            byte[] strbyte = new byte[32];
+                            data.readBytes(strbyte, 0, 32);
+                            sb.append("Cpu type: ").append(new String(strbyte)).append("\r\n");
+                        }
+                        break;
+                        case 0x08: {
+                            byte[] strbyte = new byte[32];
+                            data.readBytes(strbyte, 0, 32);
+                            sb.append("Serial mc/mmc: ").append(new String(strbyte)).append("\r\n");
+                        }
+                        break;
+                        case 0x09: {
+                            sb.append("Manufacturer ID: ").append(data.readShort()).append("\r\n");
+                            sb.append("Profile ID: ").append(data.readShort()).append("\r\n");
+                            sb.append("Profile specific type: ").append(data.readShort()).append("\r\n");
+                            ByteBuf data2 = data.readSlice(26);
+                            sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                        case 0x0A: {
+                            byte[] strbyte = new byte[26];
+                            data.readBytes(strbyte, 0, 26);
+                            sb.append("OEM copyright: ").append(new String(strbyte)).append("\r\n");
+                            sb.append("OEM ID: ").append(data.readShort()).append("\r\n");
+                            sb.append("OEM add ID: ").append(data.readInt()).append("\r\n");
+                        }
+                        break;
+                        case 0x0B: {
+                            byte[] strbyte = new byte[32];
+                            data.readBytes(strbyte, 0, 32);
+                            sb.append("Location ID: ").append(new String(strbyte)).append("\r\n");
+                        }
+                        break;
+                        case 0x0C: {
+                            byte[] strbyte = new byte[10];
+                            data.readBytes(strbyte, 0, 10);
+                            sb.append("Order number sync module 1: ").append(new String(strbyte)).append("\r\n");
+                            data.readShort();
+                            byte[] strbyte2 = new byte[2];
+                            data.readBytes(strbyte2, 0, 2);
+                            sb.append("Product version: ").append(new String(strbyte2)).append("\r\n");
+                            data.readByte();
+                            ByteBuf data2 = data.readSlice(17);
+                            sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                        case 0x0D: {
+                            byte[] strbyte = new byte[10];
+                            data.readBytes(strbyte, 0, 10);
+                            sb.append("Order number sync module 2: ").append(new String(strbyte)).append("\r\n");
+                            data.readShort();
+                            byte[] strbyte2 = new byte[2];
+                            data.readBytes(strbyte2, 0, 2);
+                            sb.append("Product version: ").append(new String(strbyte2)).append("\r\n");
+                            data.readByte();
+                            ByteBuf data2 = data.readSlice(17);
+                            sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                        case 0x0E: {
+                            byte[] strbyte = new byte[18];
+                            data.readBytes(strbyte, 0, 18);
+                            sb.append("Serial number: ").append(new String(strbyte)).append("\r\n");
+                            ByteBuf data2 = data.readSlice(14);
+                            sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");
+                        }
+                        break;
+                    }
+
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY22(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                ;
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                ;
+
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    ByteBuf infobytes = data.readSlice(20);
+                    short al1 = data.readShort();
+                    short al2 = data.readShort();
+                    int al3 = data.readInt();
+                    sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n");
+                    sb.append("al 1: ").append(Integer.toHexString(al1)).append("\r\n");
+                    sb.append("al 2: ").append(Integer.toHexString(al2)).append("\r\n");
+                    sb.append("al 3: ").append(Integer.toHexString(al3)).append("\r\n");
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+
+        }
+
+        private static StringBuilder ID_0xXY25(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY32(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY71(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY74(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                for (int i = 1; i <= ssl_count; i++) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    int cpu_type = data.readByte();
+                    int led_id = data.readByte();
+                    boolean led_onoff = (data.readByte() != 0x00);
+                    int led_flashing = data.readByte();
+
+                    sb.append("Rack number: ").append((cpu_type & 0x07)).append("\r\n");
+                    sb.append("CPU Type: ").append((cpu_type & 0x08) == 0x00 ? "Standby" : "Master").append("\r\n");
+                    sb.append("LED ID: ").append(LED_ID.valueOf(led_id)).append(" (").append(LED_ID.valueOf(led_id).description).append(")\r\n");
+                    sb.append("LED status: ").append(led_onoff).append("\r\n");
+                    switch (led_flashing) {
+                        case 0x00:
+                            sb.append("LED flashing: not.").append("\r\n");
+                            break;
+                        case 0x01:
+                            sb.append("LED blinking: normally (2 Hz).").append("\r\n");
+                            break;
+                        case 0x02:
+                            sb.append("LED blinking: slowly (0.5 Hz).").append("\r\n");
+                            break;
+                        default:
+                            sb.append("LED blinking: no information.").append("\r\n");
+                    }
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY75(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY90(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY91(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY92(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY94(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY95(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY96(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXY9C(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXYA0(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            int ssl_length = data.readShort();
+            int ssl_count = data.readShort();
+
+            try {
+                sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
+                sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
+                int i = 1;
+                while (data.isReadable()) {
+                    sb.append("Data Record: ").append(i).append("\r\n");
+                    Short id = data.readShort();
+
+                    sb.append("ID: ").append(id).append("\r\n");
+                    ByteBuf infobytes = data.readSlice(10);
+                    sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n");
+                    infobytes = data.readSlice(8);
+                    sb.append("Timestamp: ").append(readDateAndTime(infobytes).toString()).append("\r\n");
+                    sb.append("Desc: ").append(S7DiagnosticEventId.valueOf(id).getDescription()).append("\r\n");
+                    i++;
+                }
+            } catch (Exception ex) {
+                sb.append(ex);
+            }
+
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXYB1(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXYB2(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXYB3(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        private static StringBuilder ID_0xXYB4(ByteBuf data) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("It is not implemeted yet!");
+            return sb;
+        }
+
+        /*
+         * Date and time of day (BCD coded).
+         *          +----------------+
+         * Byte n   | Year   0 to 99 |
+         *          +----------------+
+         * Byte n+1 | Month  1 to 12 |
+         *          +----------------+
+         * Byte n+2 | Day    1 to 31 |
+         *          +----------------+
+         * Byte n+3 | Hour   0 to 23 |
+         *          +----------------+
+         * Byte n+4 | Minute 0 to 59 |
+         *          +----------------+
+         * Byte n+5 | Second 0 to 59 |
+         *          +----------------+
+         * Byte n+6 | ms    0 to 999 |
+         * Byte n+7 | X X X X X D O W|
+         *          +----------------+
+         * DOW: Day of weed (last 3 bits)
+         */
+        private static LocalDateTime readDateAndTime(ByteBuf data) {
+            //from Plc4XS7Protocol
+            int year = convertByteToBcd(data.readByte());
+            byte themonth = data.readByte();
+            int month = convertByteToBcd(themonth == 0x00 ? 0x01 : themonth);
+            byte theday = data.readByte();
+            int day = convertByteToBcd(theday == 0x00 ? 0x01 : theday);
+            int hour = convertByteToBcd(data.readByte());
+            int minute = convertByteToBcd(data.readByte());
+            int second = convertByteToBcd(data.readByte());
+            int milliseconds = (data.readShort() & 0xfff0) >> 4;
+
+            int cen = ((milliseconds & 0x0f00) >> 8) * 100;
+            int dec = ((milliseconds & 0x00f0) >> 4) * 10;
+            milliseconds = cen + dec + (milliseconds & 0x000f);
+            int nanoseconds = milliseconds * 1000000;
+
+            //data-type ranges from 1990 up to 2089
+            if (year >= 90) {
+                year += 1900;
+            } else {
+                year += 2000;
+            }
+
+            return LocalDateTime.of(year, month, day, hour, minute, second, nanoseconds);
+        }
+
+        /**
+         * converts incoming byte to an integer regarding used BCD format
+         *
+         * @param incomingByte the incoming byte
+         * @return converted BCD number
+         */
+        private static int convertByteToBcd(byte incomingByte) {
+            int dec = (incomingByte >> 4) * 10;
+            return dec + (incomingByte & 0x0f);
+        }
+
+        /**
+         * converts incoming Short to an integer regarding used BCD format
+         *
+         * @param incomingShort the incoming byte
+         * @return converted BCD number
+         */
+        private static short convertShortToBcd(short incomingShort) {
+            return (short) ((incomingShort >> 8) * 100 +
+                (incomingShort >> 4) * 10 +
+                (incomingShort & 0x0f));
+        }
+
+    }
+
+    public static Duration S5TimeToDuration(Short data) {
+        Duration res;
+        short t = data;
+        long tv = (short) (((t & 0x000F)) + ((t & 0x00F0) >> 4) * 10 + ((t & 0x0F00) >> 8) * 100);
+        long tb = (short) (10 * Math.pow(10, ((t & 0xF000) >> 12)));
+        long totalms = tv * tb;
+        if (totalms <= 9990000) {
+            res = Duration.ofMillis(totalms);
+        } else {
+            res = Duration.ofMillis(9990000);
+        }
+        return res;
+    }
+
+    public static Short DurationToS5Time(Duration duration) {
+        short tv = 0;
+        short tb = 0x0000_0000;
+        short s5time = 0x0000;
+        long totalms = duration.toMillis();
+
+        if ((totalms >= 0) && (totalms <= 9990000)) {
+            if (totalms <= 9990) {
+                tb = 0x0000_0000; //10 ms
+                tv = (short) (totalms / 10);
+            } else if (totalms <= 99900) {
+                tb = 0x0000_0001;// 100 ms
+                tv = (short) (totalms / 100);
+            } else if (totalms <= 999000) {
+                tb = 0x0000_0002;//1000 ms
+                tv = (short) (totalms / 1000);
+            } else if (totalms > 999000) {
+                tb = 0x0000_0003;//10000 ms
+                tv = (short) (totalms / 10000);
+            }
+
+            short uni = (short) (tv % 10);
+            short dec = (short) ((tv / 10) % 10);
+            short cen = (short) ((tv / 100) % 10);
+
+            return (short) (((tb) << 12) | (cen << 8) | (dec << 4) | (uni));
+        }
+        return s5time;
+    }
+
+    public static Duration S7TimeToDuration(Integer data) {
+        Duration res = Duration.ZERO;
+        if (data >= 0) {
+            res = res.plusMillis((long) data);
+        } else {
+            long ms = 0x8000_0000 - (data & 0x8000_0000);
+            res = res.minusMillis((long) data);
+        }
+
+        return res;
+    }
+
+    public static Integer DurationToS7Time(Duration data) {
+        Integer res = 0x0000_0000;
+        if (data.isNegative()) {
+            res = (int) data.toMillis() + 0x8000_0000;
+        } else {
+            res = (int) data.toMillis();
+        }
+        return res;
+    }
+
+    public static LocalTime S7TodToLocalTime(Integer data) {
+        if (data > 0x0526_5bff) data = 0x0526_5bff;
+        if (data < 0) data = 0x0000_0000;
+        return LocalTime.MIDNIGHT.plusNanos((long) data * 1_000_000);
+    }
+
+    public static Integer LocalTimeToS7Tod(LocalTime data) {
+        return (int) (data.toNanoOfDay() / 1_000_000);
+    }
+
+    public static LocalDate S7DateToLocalDate(Short data) {
+        LocalDate res = LocalDate.of(1990, 1, 1);
+        res = res.plusDays((long) data);
+        return res;
+    }
+
+    public static Short LocalDateToS7Date(LocalDate data) {
+        LocalDate ini = LocalDate.of(1990, 1, 1);
+        long resl = ChronoUnit.DAYS.between(ini, data);
+        return (short) resl;
+    }
+
+    /*
+     * Date and time of day (BCD coded).
+     *          +----------------+
+     * Byte n   | Year   0 to 99 |
+     *          +----------------+
+     * Byte n+1 | Month  1 to 12 |
+     *          +----------------+
+     * Byte n+2 | Day    1 to 31 |
+     *          +----------------+
+     * Byte n+3 | Hour   0 to 23 |
+     *          +----------------+
+     * Byte n+4 | Minute 0 to 59 |
+     *          +----------------+
+     * Byte n+5 | Second 0 to 59 |
+     *          +----------------+
+     * Byte n+6 | ms    0 to 999 |
+     * Byte n+7 | X X X X X D O W|
+     *          +----------------+
+     * DOW: Day of weed (last 3 bits)
+     */
+    public static LocalDateTime S7DateTimeToLocalDateTime(ByteBuf data) {
+        //from Plc4XS7Protocol
+        int year = BcdToInt(data.readByte());
+        int month = BcdToInt(data.readByte());
+        int day = BcdToInt(data.readByte());
+        int hour = BcdToInt(data.readByte());
+        int minute = BcdToInt(data.readByte());
+        int second = BcdToInt(data.readByte());
+        int millih = BcdToInt(data.readByte()) * 10;
+
+        int milll = (data.readByte() >> 4);
+
+        int milliseconds = millih + milll;
+        int nanoseconds = milliseconds * 1000000;
+        //At this point a dont need the day of week
+        //data-type ranges from 1990 up to 2089
+        if (year >= 90) {
+            year += 1900;
+        } else {
+            year += 2000;
+        }
+
+        return LocalDateTime.of(year, month, day, hour, minute, second, nanoseconds);
+    }
+
+    public static LocalDateTime S7DateAndTimeToLocalDateTime(int year, int month, int day,
+                                                             int hour, int min, int sec, int msec) {
+        int nanoseconds = msec * 1000000;
+        //At this point a dont need the day of week
+        //data-type ranges from 1990 up to 2089
+        if (year >= 90) {
+            year += 1900;
+        } else {
+            year += 2000;
+        }
+        return LocalDateTime.of(year, month, day, hour, min, sec, nanoseconds);
+    }
+
+    public static byte[] LocalDateTimeToS7DateTime(LocalDateTime data) {
+        byte[] res = new byte[8];
+
+        res[0] = ByteToBcd((data.getYear() % 100));
+        res[1] = ByteToBcd(data.getMonthValue());
+        res[2] = ByteToBcd(data.getDayOfMonth());
+        res[3] = ByteToBcd(data.getHour());
+        res[4] = ByteToBcd(data.getMinute());
+        res[5] = ByteToBcd(data.getSecond());
+
+        long ms = (long) (data.getNano() / 1_000_000);
+        res[6] = (byte) ((int) (((ms / 100) << 4) | ((ms / 10) % 10)));
+        //Java:1 (Monday) to 7 (Sunday)->S7:1 (Sunday) to 7 (Saturday)
+        byte dayofweek = (byte) ((data.getDayOfWeek().getValue() < 7) ?
+            data.getDayOfWeek().getValue() + 1 :
+            (byte) 0x01);
+        res[7] = (byte) (((ms % 10) << 4) | ((byte) (dayofweek)));
+
+        return res;
+    }
+
+
+    /**
+     * converts incoming byte to an integer regarding used BCD format
+     *
+     * @param incomingByte the incoming byte
+     * @return converted BCD number
+     */
+    private static byte ByteToBcd(int incomingByte) {
+        byte dec = (byte) ((incomingByte / 10) % 10);
+        return (byte) ((dec << 4) | (incomingByte % 10));
+    }
+
+    private static int BcdToInt(byte bcd) {
+        return (bcd >> 4) * 10 + (bcd & 0x0f);
+    }
+
+    public static void ByteToBcd(final WriteBuffer buffer, short _value) throws ParseException {
+        short incomingByte = _value;
+        byte outputByte = 0;
+        byte dec = (byte) ((incomingByte / 10) % 10);
+        outputByte = (byte) ((dec << 4) | (incomingByte % 10));
+        buffer.writeByte(outputByte);
+    }
+
+    public static int BcdToInt(final ReadBuffer buffer) throws ParseException {
+        byte bcd = buffer.readByte();
+        return (bcd >> 4) * 10 + (bcd & 0x0f);
+    }
+
+    public static int S7msecToInt(final ReadBuffer buffer) throws ParseException {
+        int centenas = BcdToInt(buffer.readUnsignedByte(4));
+        int decenas = BcdToInt(buffer.readUnsignedByte(4));
+        int unidad = BcdToInt(buffer.readUnsignedByte(4));
+        return centenas * 100 + decenas * 10 + unidad;
+    }
+
+    public static void IntToS7msec(final WriteBuffer buffer, int _value) throws ParseException {
+        int local = 0;
+        if (_value > 999) {
+            local = 999;
+        } else local = _value;
+
+        int centenas = local / 100;
+        int residual = (local - centenas * 100);
+        int decenas = (residual) / 10;
+        int unidad = residual - (decenas * 10);
+
+        buffer.writeUnsignedByte(4, (byte) centenas);
+        buffer.writeUnsignedByte(4, (byte) decenas);
+        buffer.writeUnsignedByte(4, (byte) unidad);
+    }
+
+    public static void LeftShift3(final WriteBuffer buffer, int _value) throws ParseException {
+        int valor = _value << 3;
+        buffer.writeUnsignedInt(16, valor);
+    }
+
+    public static int RightShift3(final ReadBuffer buffer) throws ParseException {
+        return buffer.readUnsignedInt(16) >> 3;
+    }
+
+    //TODO: apply only if not the last item
+    public static int EventItemLength(final ReadBuffer buffer, int valueLength) {
+        return ((valueLength % 2 == 0) || (!buffer.hasMore((valueLength + 1) * 8))) ? valueLength : valueLength + 1;
+    }
+
+
+    public static PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportErrorCode) {
+        if (dataTransportErrorCode == null) {
+            return PlcResponseCode.INTERNAL_ERROR;
+        }
+        switch (dataTransportErrorCode) {
+            case OK:
+                return PlcResponseCode.OK;
+            case NOT_FOUND:
+                return PlcResponseCode.NOT_FOUND;
+            case INVALID_ADDRESS:
+                return PlcResponseCode.INVALID_ADDRESS;
+            case DATA_TYPE_NOT_SUPPORTED:
+                return PlcResponseCode.INVALID_DATATYPE;
+            case ACCESS_DENIED:
+                return PlcResponseCode.ACCESS_DENIED;
+            default:
+                return PlcResponseCode.INTERNAL_ERROR;
+        }
+    }
+
+
+    private static byte[] wordToBytes(long data) {
+        return new byte[]{
+            (byte) ((data >> 8) & 0xff),
+            (byte) ((data >> 0) & 0xff),
+        };
+    }
+
+    private static byte[] dwordToBytes(long data) {
+        return new byte[]{
+            (byte) ((data >> 24) & 0xff),
+            (byte) ((data >> 16) & 0xff),
+            (byte) ((data >> 8) & 0xff),
+            (byte) ((data >> 0) & 0xff),
+        };
+    }
+
+    public static String ModeEventProcessing(final S7ModeEvent mode) {
+        StringBuilder sb = new StringBuilder("CPU is in : ");
+        if (ModeTransitionType.isDefined((short) mode.getMap().get("CURRENT_MODE"))) {
+            short currentmode = (short) mode.getMap().get("CURRENT_MODE");
+            sb.append(ModeTransitionType.enumForValue(currentmode).name());
+        } else {
+            sb.append("UNDEFINED");
+        }
+        return sb.toString();
+    }
+
+    public static String SysEventProcessing(final S7SysEvent event, String eventtext, HashMap<String, HashMap<String, String>> textlists) {
+        final Pattern EVENT_SIG =
+            Pattern.compile("(@[\\d]{0,3}[bycwixdrBYCWIXDR](%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@)");
+
+        final Pattern FIELDS =
+            Pattern.compile("@(?<sig>[\\d]{0,3})(?<type>[bycwixdrBYCWIXDR])(?<format>%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@");
+
+        final Pattern FIELD_FORMAT =
+            Pattern.compile("%([\\d]{0,2})([duxbsDUXBS]{1})");
+
+        Map<String, Object> map = event.getMap();
+        Matcher matcher = EVENT_SIG.matcher(eventtext);
+        Matcher fields = null;
+        Matcher fieldformat = null;
+
+        String strSig = null;
+        ByteBuf bytebuf = null;
+        int length = 0;
+        int sig = 0;
+        long value = 0;
+        String strOut = eventtext;
+        String strField = null;
+
+        while (matcher.find()) {
+            fields = FIELDS.matcher(matcher.group(0));
+            if (!fields.find()) break;
+            sig = fields.group(1) == "" ? 1 : Integer.parseInt(fields.group(1));
+            if ((sig == 0) || (sig > 2)) break;
+            String infofield = (sig == 1) ? "INFO1" : "INFO2";
+            long infovalue = (long) event.getMap().get(infofield);
+            String format = fields.group(3).toUpperCase();
+            bytebuf = (sig == 1) ?
+                Unpooled.wrappedBuffer(wordToBytes(infovalue)) :
+                Unpooled.wrappedBuffer(dwordToBytes(infovalue));
+            switch (fields.group(2).toUpperCase()) {
+                case "B":
+                    if (bytebuf.capacity() < Byte.BYTES) break;
+                    strField = String.valueOf(bytebuf.getBoolean(0));
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "Y":
+                    if (bytebuf.capacity() < Byte.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedByte(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getByte(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedByte(0);
+                        strField = Integer.toBinaryString((byte) value);
+                    } else {
+                        value = bytebuf.getByte(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "C":
+                    if (format.contains("%T#")) {
+
+                    } else {
+                        if (bytebuf.capacity() < Byte.BYTES) break;
+                        fieldformat = FIELD_FORMAT.matcher(format);
+                        if (fieldformat.find()) {
+                            length = Integer.parseInt(fieldformat.group(1));
+                            length = (length > bytebuf.capacity()) ? bytebuf.capacity() : length;
+                            strField =
+                                bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString();
+                        }
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "W":
+                    if (bytebuf.capacity() < Short.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedShort(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getShort(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedShort(0);
+                        strField = Integer.toBinaryString((short) value);
+                    } else {
+                        value = bytebuf.getShort(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "I":
+                    if (bytebuf.capacity() < Integer.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getInt(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getInt(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    break;
+                case "X":
+                    if (bytebuf.capacity() < Long.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    break;
+                case "D":
+                    if (bytebuf.capacity() < Double.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    break;
+                case "R":
+                    if (bytebuf.capacity() < Float.BYTES) break;
+                    if (format.contains("F")) {
+                        strField = String.format(format, value);
+                        strOut = strOut.replaceAll(matcher.group(0), strField);
+                    }
+                    ;
+                    break;
+            }
+        }
+
+        return strOut;
+    }
+
+    /**
+     * Symbol       Meaning
+     * ======       =======
+     *
+     * @param alarm     Alarm type from PLC.
+     * @param alarmText The text string to be processed.
+     * @param textlists List of texts for indexed replacement.
+     * @return The text string with the replacement values.
+     * @ Beginning of format string
+     * Pv           Process value number (optional)
+     * Typ          Type of process value (optional)
+     * % width      Width of the signaling field on the OP
+     * .precision   Number of decimal places (optional with format = "f")
+     * format       Process value representation mode
+     * @ End of format string
+     * <p>
+     * Type		Meaning
+     * ====             =======
+     * B		BOOL
+     * Y		BYTE
+     * C		CHARACTER
+     * W		WORD
+     * I		INTEGER
+     * X		DWORD
+     * D		DINT
+     * R		REAL
+     * <p>
+     * Representation       Format
+     * ==============       ======
+     * %[i]d                Decimal signed
+     * %[i]u                Decimal without sign
+     * %[i]x                Hexadecimal
+     * %[i].[y]f            Signed fixed point
+     * %[i]b                Binary
+     * %[i]s                Character string (STRING ANSI)
+     * %t#<Library name>    Access to text library
+     * <p>
+     * General representation:
+     * @@&gt;Associated Value>&gt;Type>&gt;Format>&gt;Library name>@
+     */
+    public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, HashMap<String, HashMap<String, String>> textlists) {
+        final Pattern ALARM_SIG =
+            Pattern.compile("(@[\\d]{0,3}[bycwixdrBYCWIXDR](%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@)");
+
+        final Pattern FIELDS =
+            Pattern.compile("@(?<sig>[\\d]{0,3})(?<type>[bycwixdrBYCWIXDR])(?<format>%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@");
+
+        final Pattern FIELD_FORMAT =
+            Pattern.compile("%([\\d]{0,2})([duxbsDUXBS]{1})");
+
+        Map<String, Object> map = alarm.getMap();
+        Matcher matcher = ALARM_SIG.matcher(alarmText);
+        Matcher fields = null;
+        Matcher fieldformat = null;
+
+        String strSig = null;
+        ByteBuf bytebuf = null;
+        int length = 0;
+        int sig = 0;
+        long value = 0;
+        String strOut = new String(alarmText);
+        String strField = null;
+
+        while (matcher.find()) {
+            fields = FIELDS.matcher(matcher.group(0));
+            if (!fields.find()) break;
+            sig = fields.group(1) == "" ? 1 : Integer.parseInt(fields.group(1));
+            strSig = "SIG_" + sig + "_DATA";
+            if ((((short) map.get("ASSOCIATED_VALUES")) == 0) ||
+                (sig > ((short) map.get("ASSOCIATED_VALUES")))) break;
+            bytebuf = Unpooled.wrappedBuffer((byte[]) map.get(strSig));
+            String format = fields.group(3).toUpperCase();
+            switch (fields.group(2).toUpperCase()) {
+                case "B":
+                    if (bytebuf.capacity() < Byte.BYTES) break;
+                    strField = String.valueOf(bytebuf.getBoolean(0));
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "Y":
+                    if (bytebuf.capacity() < Byte.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedByte(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getByte(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedByte(0);
+                        strField = Integer.toBinaryString((byte) value);
+                    } else {
+                        value = bytebuf.getByte(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "C":
+                    if (format.contains("%T#")) {
+
+                    } else {
+                        if (bytebuf.capacity() < Byte.BYTES) break;
+                        fieldformat = FIELD_FORMAT.matcher(format);
+                        if (fieldformat.find()) {
+                            length = Integer.parseInt(fieldformat.group(1));
+                            length = (length > bytebuf.capacity()) ? bytebuf.capacity() : length;
+                            strField =
+                                bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString();
+                        }
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "W":
+                    if (bytebuf.capacity() < Short.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedShort(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getShort(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedShort(0);
+                        strField = Integer.toBinaryString((short) value);
+                    } else {
+                        value = bytebuf.getShort(0);
+                        strField = String.format(format, value);
+                    }
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "I":
+                    if (bytebuf.capacity() < Integer.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getInt(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getInt(0);
+                        strField = String.format(format, value);
+                    }
+                    ;
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "X":
+                    if (bytebuf.capacity() < Long.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    }
+                    ;
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "D":
+                    if (bytebuf.capacity() < Double.BYTES) break;
+                    if (format.contains("U")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        String strReplace = format.replace("U", "d");
+                        strField = String.format(strReplace, value);
+                    } else if (format.contains("D")) {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    } else if (format.contains("B")) {
+                        value = bytebuf.getUnsignedInt(0);
+                        strField = Long.toBinaryString(value);
+                    } else {
+                        value = bytebuf.getLong(0);
+                        strField = String.format(format, value);
+                    }
+                    ;
+                    strOut = strOut.replaceAll(matcher.group(0), strField);
+                    ;
+                    break;
+                case "R":
+                    if (bytebuf.capacity() < Float.BYTES) break;
+                    if (format.contains("F")) {
+                        strField = String.format(format, value);
+                        strOut = strOut.replaceAll(matcher.group(0), strField);
+                    }
+                    ;
+                    break;
+
+            }
+        }
+
+        return strOut;
+    }
+
+    public static LocalTime parseTiaTime(ReadBuffer io) {
+        try {
+            int millisSinceMidnight = io.readInt(32);
+            return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
+                millisSinceMidnight, ChronoUnit.MILLIS);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeTiaTime(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing TIME not implemented");
+    }
+
+    public static LocalTime parseS5Time(ReadBuffer io) {
+        try {
+            int stuff = io.readInt(16);
+            // TODO: Implement this correctly.
+            throw new NotImplementedException("S5TIME not implemented");
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeS5Time(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing S5TIME not implemented");
+
+    }
+
+    public static LocalTime parseTiaLTime(ReadBuffer io) {
+        throw new NotImplementedException("LTIME not implemented");
+    }
+
+    public static void serializeTiaLTime(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing LTIME not implemented");
+    }
+
+    public static LocalTime parseTiaTimeOfDay(ReadBuffer io) {
+        try {
+            long millisSinceMidnight = io.readUnsignedLong(32);
+            return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
+                millisSinceMidnight, ChronoUnit.MILLIS);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeTiaTimeOfDay(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing TIME_OF_DAY not implemented");
+    }
+
+    public static LocalDate parseTiaDate(ReadBuffer io) {
+        try {
+            int daysSince1990 = io.readUnsignedInt(16);
+            return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    public static void serializeTiaDate(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing DATE not implemented");
+    }
+
+    //TODO: Call BCD converter
+    public static LocalDateTime parseTiaDateTime(ReadBuffer io) {
+        try {
+            int year = io.readUnsignedInt(16);
+            int month = io.readUnsignedInt(8);
+            int day = io.readUnsignedInt(8);
+            // Skip day-of-week
+            io.readByte();
+            int hour = io.readByte();
+            int minute = io.readByte();
+            int second = io.readByte();
+            int nanosecond = io.readUnsignedInt(24);
+            // Skip day-of-week
+            io.readByte();
+
+            return LocalDateTime.of(year, month, day, hour, minute, second, nanosecond);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void serializeTiaDateTime(WriteBuffer io, PlcValue value) {
+        throw new NotImplementedException("Serializing DATE_AND_TIME not implemented");
+    }
+
+    public static String parseS7Char(ReadBuffer io, String encoding) {
+        if ("UTF-8".equalsIgnoreCase(encoding)) {
+            return io.readString(8, encoding);
+        } else if ("UTF-16".equalsIgnoreCase(encoding)) {
+            return io.readString(16, encoding);
+        } else {
+            throw new PlcRuntimeException("Unsupported encoding");
+        }
+    }
+
+    public static String parseS7String(ReadBuffer io, int stringLength, String encoding) {
+        try {
+            if ("UTF-8".equalsIgnoreCase(encoding)) {
+                // 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.readUnsignedShort(8);
+
+                final byte[] byteArray = new byte[totalStringLength];
+                for (int i = 0; (i < stringLength) && io.hasMore(8); i++) {
+                    final byte curByte = io.readByte();
+                    if (i < totalStringLength) {
+                        byteArray[i] = curByte;
+                    } else {
+                        // Gobble up the remaining data, which is not added to the string.
+                        i++;
+                        for (; (i < stringLength) && io.hasMore(8); i++) {
+                            io.readByte();
+                        }
+                        break;
+                    }
+                }
+                return new String(byteArray, StandardCharsets.UTF_8);
+            } else if ("UTF-16".equalsIgnoreCase(encoding)) {
+                // This is the maximum number of bytes a string can be long.
+                int maxLength = io.readUnsignedInt(16);
+                // This is the total length of the string on the PLC (Not necessarily the number of characters read)
+                int totalStringLength = io.readUnsignedInt(16);
+
+                final byte[] byteArray = new byte[totalStringLength * 2];
+                for (int i = 0; (i < stringLength) && io.hasMore(16); i++) {
+                    final short curShort = io.readShort(16);
+                    if (i < totalStringLength) {
+                        byteArray[i * 2] = (byte) (curShort >>> 8);
+                        byteArray[(i * 2) + 1] = (byte) (curShort & 0xFF);
+                    } else {
+                        // Gobble up the remaining data, which is not added to the string.
+                        i++;
+                        for (; (i < stringLength) && io.hasMore(16); i++) {
+                            io.readShort(16);
+                        }
+                        break;
+                    }
+                }
+                return new String(byteArray, StandardCharsets.UTF_16);
+            } else {
+                throw new PlcRuntimeException("Unsupported string encoding " + encoding);
+            }
+        } catch (ParseException e) {
+            throw new PlcRuntimeException("Error parsing string", e);
+        }
+    }
+
+    /*
+     * A variable of data type CHAR (character) occupies one byte.
+     */
+    public static void serializeS7Char(WriteBuffer io, PlcValue value, String encoding) {
+        // TODO: Need to implement the serialization or we can't write strings
+        if ("UTF-8".equalsIgnoreCase(encoding)) {
+            //return io.readString(8, encoding);
+        } else if ("UTF-16".equalsIgnoreCase(encoding)) {
+            //return io.readString(16, encoding);
+        } else {
+            throw new PlcRuntimeException("Unsupported encoding");
+        }
+    }
+
+    /*           +-------------------+
+     * Byte n     | Maximum length    | (k)
+     *            +-------------------+
+     * Byte n+1   | Current Length    | (m)
+     *            +-------------------+
+     * Byte n+2   | 1st character     | \         \
+     *            +-------------------+  |         |
+     * Byte n+3   | 2st character     |  | Current |
+     *            +-------------------+   >        |
+     * Byte ...   | ...               |  | length  |  Maximum
+     *            +-------------------+  |          >
+     * Byte n+m+1 | mth character     | /          |  length
+     *            +-------------------+            |
+     * Byte ...   | ...               |            |
+     *            +-------------------+            |
+     * Byte ...   | ...               |           /
+     *            +-------------------+
+     * For this version, the user must read the maximum acceptable length in
+     * the string in a first instance.
+     * Then the user application should avoid the envelope of the adjacent
+     * fields passing the maximum length in "stringLength".
+     * If your application does not handle S7string, you can handle
+     * the String as char arrays from your application.
+     */
+    public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, String encoding) {
+        byte k = (byte) ((stringLength > 250) ? 250 : stringLength);
+        byte m = (byte) value.getString().length();
+        m = (m > k) ? k : m;
+        byte[] chars = new byte[m];
+        for (int i = 0; i < m; ++i) {
+            char c = value.getString().charAt(i);
+            chars[i] = (byte) c;
+        }
+
+        try {
+            io.writeByte(k);
+            io.writeByte(m);
+            io.writeByteArray(chars);
+        } catch (ParseException ex) {
+            Logger.getLogger(StaticHelper.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+}
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7EventHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7EventHelper.java
deleted file mode 100644
index 02ff5bb..0000000
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7EventHelper.java
+++ /dev/null
@@ -1,1846 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.s7.utils;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.buffer.Unpooled;
-import java.nio.charset.Charset;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.temporal.ChronoUnit;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.s7.events.S7AlarmEvent;
-import org.apache.plc4x.java.s7.events.S7ModeEvent;
-import org.apache.plc4x.java.s7.events.S7SysEvent;
-import org.apache.plc4x.java.s7.readwrite.DataTransportErrorCode;
-import org.apache.plc4x.java.s7.readwrite.ModeTransitionType;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-
-
-/**
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1|
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  \__________/\__________/\____________________/
- *   Module      Number of   Number of the partial 
- *   class       the partial list
- *               list 
- *               extract
- * 
- *  <b>Module Class:</b>
- *  +--------------+-----------------+ 
- *  | Module class | Coding (Binary) |
- *  +--------------|-----------------+
- *  |     CPU      |      0000       | 
- *  +--------------|-----------------+
- *  |     IM       |      0100       | 
- *  +--------------|-----------------+
- *  |     FM       |      1000       | 
- *  +--------------|-----------------+
- *  |     CP       |      1100       | 
- *  +--------------|-----------------+
- * 
- *  <b>Possible SSL Partial Lists:</b>
- *  +-----------------------------------------------------------|--------------+
- *  | Module class                                              |    SSL-ID    |
- *  +-----------------------------------------------------------|--------------+
- *  | Module identification                                     |    16#xy11   |
- *  +-----------------------------------------------------------|--------------+
- *  | CPU characteristics                                       |    16#xy12   |
- *  +-----------------------------------------------------------|--------------+
- *  | User memory areas                                         |    16#xy13   |
- *  +-----------------------------------------------------------|--------------+
- *  | System areas                                              |    16#xy14   |
- *  +-----------------------------------------------------------|--------------+
- *  | Block types                                               |    16#xy15   |
- *  +-----------------------------------------------------------|--------------+
- *  | Interrupt status                                          |    16#xy22   |
- *  +-----------------------------------------------------------|--------------+
- *  | Assignment between process image partitions and OBs       |    16#xy25   |
- *  +-----------------------------------------------------------|--------------+
- *  | Communication status data                                 |    16#xy32   |
- *  +-----------------------------------------------------------|--------------+
- *  | H CPU group information                                   |    16#xy71   |
- *  +-----------------------------------------------------------|--------------+
- *  | Status of the module LEDs                                 |    16#xy74   |
- *  +-----------------------------------------------------------|--------------+
- *  | Switched DP slaves in the H-system                        |    16#xy75   |
- *  +-----------------------------------------------------------|--------------+
- *  | Module status information                                 |    16#xy91   |
- *  +-----------------------------------------------------------|--------------+
- *  | Rack / station status information                         |    16#xy92   |
- *  +-----------------------------------------------------------|--------------+
- *  | Rack / station status information                         |    16#xy94   |
- *  +-----------------------------------------------------------|--------------+
- *  | Extended DP master system / PROFINET IO system information|    16#xy95   |
- *  +-----------------------------------------------------------|--------------+
- *  | Module status information, PROFINET IO and PROFIBUS DP    |    16#xy96   |
- *  +-----------------------------------------------------------|--------------+
- *  | Tool changer information (PROFINET IO)                    |    16#xy9C   |
- *  +-----------------------------------------------------------|--------------+
- *  | Diagnostic buffer of the CPU                              |    16#xyA0   |
- *  +-----------------------------------------------------------|--------------+
- *  | Module diagnostic information (data record 0)             |    16#xyB1   |
- *  +-----------------------------------------------------------|--------------+
- *  | Module diagnostic information (data record 1),            |    16#xyB2   |
- *  | geographical address                                      |              |
- *  +-----------------------------------------------------------|--------------+
- *  | Module diagnostic information (data record 1),            |    16#xyB3   |
- *  | logical address                                           |              |
- *  +-----------------------------------------------------------|--------------+
- *  | Diagnostic data of a DP slave                             |    16#xyB4   |
- *  +-----------------------------------------------------------|--------------+
- * 
- * 
- * @author cgarcia
- */
-
-public class S7EventHelper {
-  
-    /**
-     * 
-     */
-    public enum OB {
-        FREE_CYC(0X0000,"OB1 Free cycle"),
-        
-        //Time of day
-        TOD_INT0(0X000A,"OB10 Time of day interrupt"),
-        TOD_INT1(0X000B,"OB11 Time of day interrupt"),
-        TOD_INT2(0X000C,"OB12 Time of day interrupt"),
-        TOD_INT3(0X000D,"OB13 Time of day interrupt"),
-        TOD_INT4(0X000E,"OB14 Time of day interrupt"),
-        TOD_INT5(0X000F,"OB15 Time of day interrupt"),
-        TOD_INT6(0X0010,"OB16 Time of day interrupt"),
-        TOD_INT7(0X0011,"OB17 Time of day interrupt"),        
-        
-        //Time delay
-        DEL_INT0(0X0014,"OB20 Time delay interrupt"),
-        DEL_INT1(0X0015,"OB21 Time delay interrupt"),
-        DEL_INT2(0X0016,"OB22 Time delay interrupt"),
-        DEL_INT3(0X0017,"OB23 Time delay interrupt"),        
-        
-        //Cyclic
-        CYC_INT0(0X001E,"OB30 Cyclic interrupt"),
-        CYC_INT1(0X001F,"OB31 Cyclic interrupt"),
-        CYC_INT2(0X0020,"OB32 Cyclic interrupt"),
-        CYC_INT3(0X0021,"OB33 Cyclic interrupt"),
-        CYC_INT4(0X0022,"OB34 Cyclic interrupt"),
-        CYC_INT5(0X0023,"OB35 Cyclic interrupt"),
-        CYC_INT6(0X0024,"OB36 Cyclic interrupt"),
-        CYC_INT7(0X0025,"OB37 Cyclic interrupt"),
-        CYC_INT8(0X0026,"OB38 Cyclic interrupt"),
-                
-        //Hardware interrupts
-        HW_INT0(0X0028,"OB40 Hardware interrupt"),
-        HW_INT1(0X0029,"OB41 Hardware interrupt"),
-        HW_INT2(0X002A,"OB42 Hardware interrupt"),
-        HW_INT3(0X002B,"OB43 Hardware interrupt"),
-        HW_INT4(0X002C,"OB44 Hardware interrupt"),
-        HW_INT5(0X002D,"OB45 Hardware interrupt"),
-        HW_INT6(0X002E,"OB46 Hardware interrupt"),
-        HW_INT7(0X002F,"OB47 Hardware interrupt"),
-        
-        //Startup
-        BACKGROUND(0X005A,"OB90 Background"),
-        COMPLETE_RESTART(0X0064,"OB100 Startup"),
-        RESTART(0X0064,"OB101 Background"),
-        COLD_RESTART(0X005A,"OB101 Background"),
-        
-        //Fault interrupts
-        CYC_FLT(0X0051,"OB80 Time execution error interrupt"),
-        PS_FLT(0X0051,"OB81 Power supply interrupt"),
-        IO_FLT1(0X0052,"OB82 Module diagnostic interrupt"),
-        IO_FLT2(0X0053,"OB83 Module change interrupt"),
-        CPU_FLT(0X0054,"OB84 CPU hardware error interrupt"),        
-        OBNL_FLT(0X0055,"OB85 Program execution error interrupt"),
-        RACK_FLT(0X0056,"OB86 Rack fault interrupt"),
-        COMM_FLT(0X0057,"OB87 Communication error interrupt"),        
-        BREAKUP_ERR(0X0058,"OB88 Process interrupt"),        
-        SYNC_ERR(0X0079,"OB120 Synchronous error interrupt"),
-        PROG_ERR(0X0079,"OB121 Program error interrupt"),
-        MOD_ERR(0X007A,"OB122 Module error interrupt");
-
-        private int code;
-        private String description;
-
-        private static final Map<Integer, OB> map;
-
-        static {
-            map = new HashMap<>();
-            for (OB obid : OB.values()) {
-                map.put(obid.code, obid);
-            }
-        }         
-        
-        OB(final int code, final String description){
-            this.code = code;
-            this.description = description;
-        }
-
-        public int getCode(){
-            return code;
-        }
-
-        public String getDescription(){
-            return description;
-        }
-
-        public static OB valueOf(int code) {
-            return map.get(code);
-        }            
-        
-        
-    }    
-    
-    
-    /**
-     * 
-     */
-    public enum MODULE{
-        CPU(0X00),
-        IM(0X04),
-        FM(0X80),
-        CP(0XC0);
-        
-        private int code;
-        
-        MODULE(final int code){
-            this.code = code;
-        }
-        
-        public int getCode(){
-            return code;
-        }        
-    }
-    
-    /**
-     * 
-     */
-    public enum LED_ID {
-        SF(0X0001,"Group error"),
-        INTF(0X0002,"Internal error"),
-        EXTF(0X0003,"External error"),        
-        RUN(0X0004,"RUN"),        
-        STOP(0X0005,"STOP"),        
-        FRCE(0X0006,"Force"),        
-        CRST(0X0007,"Cold restart"),        
-        BAF(0X0008,"Battery fault"),        
-        USR(0X0009,"User defined"),        
-        USR1(0X000A,"User defined"),        
-        BUS1F(0X000B,"Bus error interface 1"),
-        BUS2F(0X000C,"Bus error interface 2"),
-        REDF(0X000D,"Redundancy error"),
-        MSTR(0X000E,"Master"),
-        RACK0(0X000F,"Rack number 0"),
-        RACK1(0X0010,"Rack number 1"),
-        RACK2(0X0011,"Rack number 2"),
-        IFM1F(0X0012,"Interface error interface module 1"),
-        IFM2F(0X0013,"Interface error interface module 2"),
-        BUS3F(0X0014,"Bus error interface 3"),
-        MAINT(0X0015,"Maintenance demand"),
-        DC24V(0X0016,"DC24V"),
-        BUS5F(0X0017,"Bus error interface 5"),
-        BUS8F(0X0018,"Bus error interface 8"),
-        IF(0X0080,"Init failure"),
-        UF(0X0081,"User failure"),
-        MF(0X0082,"Monitoring failure"),
-        CF(0X0083,"Communication failure"),
-        TF(0X0084,"Task failure"),
-        APPL_STATE_RED(0X00EC,"APPL_STATE_RED"),
-        APPL_STATE_GREEN(0X00ED,"APPL_STATE_GREEN");
-
-        private int code;
-        private String description;
-
-        private static final Map<Integer, LED_ID> map;
-
-        static {
-            map = new HashMap<>();
-            for (LED_ID ledid : LED_ID.values()) {
-                map.put(ledid.code, ledid);
-            }
-        }         
-        
-        LED_ID(final int code, final String description){
-            this.code = code;
-            this.description = description;
-        }
-
-        public int getCode(){
-            return code;
-        }
-
-        public String getDescription(){
-            return description;
-        }
-
-        public static LED_ID valueOf(int code) {
-            return map.get(code);
-        }            
-        
-        
-    }
-        
-    /**
-     * 
-     */
-    public enum CPU_CHARACTERISTICS {
-        CH_0x0000(0X0000,"MC7 processing unit (group with index 0000)"),
-        CH_0x0001(0X0001,"MC7 processing generating code"),
-        CH_0x0002(0X0002,"MC7 interpreter"),
-        
-        CH_0x0100(0X0100,"Time system (group with index 0100)"),
-        CH_0x0101(0X0101,"1 ms resolution"),
-        CH_0x0102(0X0102,"10 ms resolution"),
-        CH_0x0103(0X0103,"No real time clock"),
-        CH_0x0104(0X0104,"BCD time-of-day format"),
-        CH_0x0105(0X0105,"All time-of-day functions"),
-        CH_0x0106(0X0106,"SFC 78 \"OB_RT\" is available"),
-        
-        CH_0x0200(0X0200,"System response (group with index 0200)"),
-        CH_0x0201(0X0201,"Capable of multiprocessor mode"),
-        CH_0x0202(0X0202,"Cold restart, warm restart and hot restart possible"),
-        CH_0x0203(0X0203,"Cold restart and hot restart possible"),
-        CH_0x0204(0X0204,"Warm restart and hot restart possible"),
-        CH_0x0205(0X0205,"Only warm restart possible"),
-        CH_0x0206(0X0206,"New distributed I/O configuration is possible during\n" +
-                            "RUN by using predefined resources"),
-        CH_0x0207(0X0207,"H-CPU in stand-alone mode: New distributed I/O configuration\n" +
-                            "is possible during RUN by using predefined resources"),
-        CH_0x0208(0X0208,"For taking motion control functionality into account"),
-        
-        CH_0x0300(0X0300,"MC7 Language description of the CPU (group with index 0300)"),
-        CH_0x0301(0X0301,"Reserved"),
-        CH_0x0302(0X0302,"All 32 bit fixed-point instructions"),
-        CH_0x0303(0X0303,"All floating-point instructions"),
-        CH_0x0304(0X0304,"sin, asin, cos, acos, tan, atan, sqr, sqrt, ln, exp"),
-        CH_0x0305(0X0305,"Accumulator 3/accumulator 4 with corresponding instructions\n" +
-                            "(ENT,PUSH,POP,LEAVE)"),
-        CH_0x0306(0X0306,"Master Control Relay instructions"),
-        CH_0x0307(0X0307,"Address register 1 exists with corresponding instructions"),
-        CH_0x0308(0X0308,"Address register 2 exists with corresponding instructions"),
-        CH_0x0309(0X0309,"Operations for area-crossing addressing"),
-        CH_0x030A(0X030A,"Operations for area-internal addressing"),
-        CH_0x030B(0X030B,"All memory-indirect addressing instructions for bit memory (M)"),
-        CH_0x030C(0X030C,"All memory-indirect addressing instructions for data blocks (DB)"),
-        CH_0x030D(0X030D,"All memory-indirect addressing instructions for data blocks (DI)"),
-        CH_0x030E(0X030E,"All memory-indirect addressing instructions for local data (L)"),
-        CH_0x030F(0X030F,"All instructions for parameter transfer in FCs"),
-        CH_0x0310(0X0310,"Memory bit edge instructions for process image input (I)"),
-        CH_0x0311(0X0311,"Memory bit edge instructions for process image output (Q)"),
-        CH_0x0312(0X0312,"Memory bit edge instructions for bit memory (M)"),
-        CH_0x0313(0X0313,"Memory bit edge instructions for data blocks (DB)"),
-        CH_0x0314(0X0314,"Memory bit edge instructions for data blocks (DI)"),
-        CH_0x0315(0X0315,"Memory bit edge instructions for local data (L)"),
-        CH_0x0316(0X0316,"Dynamic evaluation of the FC bit"),
-        CH_0x0317(0X0317,"Dynamic local data area with the corresponding instructions"),
-        CH_0x0318(0X0318,"Reserved"),
-        CH_0x0319(0X0319,"Reserved"),
-        
-        CH_0x0401(0X0401,"SFC 87 \"C_DIAG\" is available"),
-        CH_0x0402(0X0402,"SFC 88 \"C_CNTRL\" is available)");
-
-        private int code;
-        private String description;
-
-        private static final Map<Integer, CPU_CHARACTERISTICS > map;
-
-        static {
-            map = new HashMap<>();
-            for (CPU_CHARACTERISTICS  cpuc : CPU_CHARACTERISTICS.values()) {
-                map.put(cpuc.code, cpuc);
-            }
-        }         
-        
-        CPU_CHARACTERISTICS(final int code, final String description){
-            this.code = code;
-            this.description = description;
-        }
-
-        public int getCode(){
-            return code;
-        }
-
-        public String getDescription(){
-            return description;
-        }
-
-        public static CPU_CHARACTERISTICS valueOf(int code) {
-            return map.get(code);
-        }            
-        
-        
-    }    
-            
-    /**
-     *
-     */
-    public enum SSL {
-    ID_0x0011(0x0011,"Module identification."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY11(data);
-        }  
-        
-    },
-    ID_0x0012(0x0012,"CPU characteristics ."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY12(data);
-        }
-        
-    },
-    ID_0x0013(0x0013,"User memory areas."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY13(data);
-        }
-        
-    },
-    ID_0x0014(0x0014,"System areas."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY14(data);
-        }
-        
-    },
-    ID_0x0015(0x0015,"Block types."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY15(data);
-        }
-        
-    },
-    ID_0x001C(0x001C,"Component identification."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY1C(data);
-        }
-        
-    },    
-    ID_0x0022(0x0022,"Interrupt status."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY22(data);
-        }
-        
-    },
-    ID_0x0025(0x0025,"Assignment between process image partitions and OBs."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY25(data);
-        }
-        
-    },
-    ID_0x0032(0x0032,"Communication status data."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY32(data);
-        }
-        
-    },
-    ID_0x0071(0x0071,"H CPU group information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY71(data);
-        }
-        
-    },
-    ID_0x0074(0x0074,"Status of the module LEDs."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY74(data);
-        }
-        
-    },
-    ID_0x0075(0x0075,"Switched DP slaves in the H-system."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY75(data);
-        }
-        
-    },
-    ID_0x0090(0x0090,"DP Master System Information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY90(data);
-        }
-        
-    },    
-    ID_0x0091(0x0091,"Module status information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY91(data);
-        }
-        
-    },
-    ID_0x0092(0x0092,"Rack / station status information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY92(data);
-        }
-        
-    },
-    ID_0x0094(0x0094,"Rack / station status information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY94(data);
-        }
-        
-    },    
-    ID_0x0095(0x0095,"Extended DP master system / PROFINET IO system information."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY95(data);
-        }
-        
-    },
-    ID_0x0096(0x0096,"Module status information, PROFINET IO and PROFIBUS DP."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY96(data);
-        }
-        
-    },
-    ID_0x009C(0x009C,"Tool changer information (PROFINET IO)."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXY9C(data);
-        }
-        
-    },
-    ID_0x00A0(0x00A0,"Diagnostic buffer of the CPU."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXYA0(data);
-        }
-        
-    },
-    ID_0x00B1(0x00B1,"Module diagnostic information (data record 0) ."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXYB1(data);
-        }
-        
-    },
-    ID_0x00B2(0x00B2,"Module diagnostic information (data record 1),geographical address."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXYB2(data);
-        }
-        
-    },
-    ID_0x00B3(0x00B3,"Module diagnostic information (data record 1),logical address."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXYB3(data);
-        }
-        
-    },
-    ID_0x00B4(0x00B4,"Diagnostic data of a DP slave."){
-        @Override
-        public StringBuilder execute(ByteBuf data) {
-            return ID_0xXYB4(data);
-        }
-        
-    };
-
-    private int code;
-    private String description;
-    
-    private static final Map<Integer, SSL> map;
-    
-    static {
-        map = new HashMap<>();
-        for (SSL subssl : SSL.values()) {
-            map.put(subssl.code, subssl);
-        }
-    }    
-    
-    SSL(final int code, final String description){
-        this.code = code;
-        this.description = description;
-    }
-    
-    public int getCode(){
-        return code;
-    }
-    
-    public String getDescription(){
-        return description;
-    }
-    
-    public static SSL valueOf(int code) {
-        return map.get(code);
-    }    
-    
-    public abstract StringBuilder execute(ByteBuf data);
-    
-    private static StringBuilder ID_0xXY11(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-
-                sb.append("Index: ").append(data.readShort()).append("\r\n");
-                byte[] bytestr = new byte[20];
-                data.readBytes(bytestr, 0, 20);
-                sb.append("Mlfb (Order number): ").append(new String(bytestr)).append("\r\n");
-                sb.append("BGTyp (Moduler type ID): ").append(data.readShort()).append("\r\n");                
-                sb.append("Ausbg (Version of the module/hardware version): ").append(data.readShort()).append("\r\n");
-                sb.append("Ausbe (Firmware version): ").append(data.readShort()).append("\r\n");
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }    
-    
-    private static StringBuilder ID_0xXY12(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                int code = data.readShort();
-                sb.append(CPU_CHARACTERISTICS.valueOf(code)).append(": ").
-                        append(CPU_CHARACTERISTICS.valueOf(code).getDescription()).append("\r\n");
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }        
-    
-    private static StringBuilder ID_0xXY13(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                sb.append("Index: ").append(data.readShort()).append("\r\n");
-                int code = data.readShort();
-                int size = data.readInt();
-                int mode = data.readShort();
-                int granu = data.readShort();
-                int ber1 = data.readInt();
-                int be1egt1 = data.readInt();
-                int block1 = data.readInt();
-                int ber2 = data.readInt();
-                int be1egt2 = data.readInt();
-                int block2 = data.readInt();
-                
-                switch(code){
-                    case 0x0001:sb.append("Code (Memory Type): ").append("Volatile memory (RAM)\r\n");
-                        break;
-                    case 0x0002:sb.append("Code (Memory Type): ").append("Non-volatile memory (FEPROM)\r\n");
-                        break;
-                    case 0x0003:sb.append("Code (Memory Type): ").append("mixed memory (RAM + FEPROM)\r\n");
-                        break;
-                }
-                sb.append("Size (Total size of the selected memory (total of area 1 and area 2)): ").append(size).append("\r\n"); 
-                
-                sb.append("Mode (Volatile memory area): ").append(((mode & 0x0001) != 0)).append("\r\n"); 
-                sb.append("Mode (Non-volatile memory area): ").append(((mode & 0x0002) != 0)).append("\r\n"); 
-                sb.append("Mode (Mixed memory area): ").append(((mode & 0x0004) != 0)).append("\r\n"); 
-                sb.append("Mode (Code and data separate): ").append(((mode & 0x0008) != 0)).append("\r\n");
-                sb.append("Mode (Code and data together): ").append(((mode & 0x0010) != 0)).append("\r\n");
-                
-                sb.append("Granu (Always zero): ").append(granu).append("\r\n"); 
-                
-                sb.append("Ber1 (Size of the volatile memory area in bytes): ").append(ber1).append("\r\n");  
-                sb.append("Belegt1 (Size of the volatile memory area being used): ").append(be1egt1).append("\r\n");
-                sb.append("Block1 (Largest free block in the volatile memory area): ").append(block1).append("\r\n");
-                
-                sb.append("Ber2 (Size of the non-volatile memory area in bytes): ").append(ber2).append("\r\n");  
-                sb.append("Belegt2 (Size of the non-volatile memory area being used): ").append(be1egt2).append("\r\n");
-                sb.append("Block2 (Largest free block in the non-volatile memory area): ").append(block2).append("\r\n");                
-                               
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }        
-     
-    private static StringBuilder ID_0xXY14(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            for (int i=1; i <= ssl_count; i++){
-                int index = data.readShort(); 
-                int code = data.readShort();
-                int quantity = data.readShort();
-                int reman = data.readShort();
-                
-                sb.append("Data Record: ").append(i).append("\r\n");
-                sb.append("Index: ").append(index).append(" System area: ");
-                switch(index) {
-                    case 0x0001: sb.append("PII (number in bytes)").append("\r\n");
-                        break;
-                    case 0x0002: sb.append("PIQ (number in bytes))").append("\r\n");
-                        break;
-                    case 0x0003: sb.append("memory (number in bits)").append("\r\n");
-                        break;
-                    case 0x0004: sb.append("timers (number)").append("\r\n");
-                        break;
-                    case 0x0005: sb.append("counter (number)").append("\r\n");
-                        break;
-                    case 0x0006: sb.append("number of bytes in the logical address area)").append("\r\n");
-                        break;
-                    case 0x0007: sb.append("local data (entire local data area of the CPU in bytes)").append("\r\n");
-                        break;
-                    case 0x0008: sb.append("memory (number in bytes)").append("\r\n");
-                        break;
-                    case 0x0009: sb.append("local data (entire local data area of the CPU in Kbytes)").append("\r\n");
-                        break;                        
-                }
-                sb.append("Code: ").append(code).append(" Memory type: ");
-                switch(code) {
-                    case 0x0001: sb.append("volatile memory (RAM)").append("\r\n");
-                        break;
-                    case 0x0002: sb.append("non-volatile memory (FEPROM)").append("\r\n");
-                        break; 
-                    case 0x0003: sb.append("mixed memory (RAM and FEPROM)").append("\r\n");
-                        break;                        
-                }
-                sb.append("Quantity: ").append(quantity).append("\r\n");
-                sb.append("Reman: ").append(reman).append("\r\n");
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }    
-       
-    private static StringBuilder ID_0xXY15(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");;
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");;
-
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                int type = data.readShort();
-                switch(type){
-                    case 0x0800: sb.append("Block type: OB\r\n");
-                        break;
-                    case 0x0A00: sb.append("Block type: DB\r\n");
-                        break;
-                    case 0x0B00: sb.append("Block type: SDB\r\n");
-                        break;
-                    case 0x0C00: sb.append("Block type: FC\r\n");
-                        break;
-                    case 0x0E00: sb.append("Block type: FB\r\n");
-                        break;
-                    default: 
-                } 
-                sb.append("Maximum number of blocks of the type: ").append(data.readShort()).append("\r\n"); ;           
-                sb.append("Maximum total size of the object to be loaded in Kbytes: ").append(data.readShort()).append("\r\n"); ;
-                sb.append("Maximum length of the work memory part of a block in bytes: ").append(data.readInt()).append("\r\n"); ;                
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }
-          
-    private static StringBuilder ID_0xXY1C(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-       try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");;
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");;
-
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                int index = data.getShort(data.readerIndex());
-                int index_b0 = data.readByte();
-                int index_b1 = data.readByte();
-                sb.append("Index: ").append(index).append("\r\n");                
-                sb.append("Index b1: ").append(index_b1).append("\r\n");
-                
-                switch(index_b1){
-                    case 0x01: 
-                    case 0x02: { 
-                        byte[] strbyte = new byte[24];
-                        data.readBytes(strbyte, 0, 24);
-                        sb.append("Name: ").append(new String(strbyte)).append("\r\n");
-                        ByteBuf  data2 = data.readSlice(8);   
-                        sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                      
-                    };
-                        break;                        
-                    case 0x03: {
-                        byte[] strbyte = new byte[32];                        
-                        data.readBytes(strbyte, 0, 32);
-                        sb.append("Tag: ").append(new String(strbyte)).append("\r\n");                        
-                    };
-                        break;                        
-                    case 0x04: {
-                        byte[] strbyte = new byte[26];                        
-                        data.readBytes(strbyte, 0, 26);
-                        sb.append("Copyright: ").append(new String(strbyte)).append("\r\n");   
-                        ByteBuf  data2 = data.readSlice(6);   
-                        sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                     
-                    };
-                        break;                        
-                    case 0x05: {
-                        byte[] strbyte = new byte[24];                        
-                        data.readBytes(strbyte, 0, 24);
-                        sb.append("Serial: ").append(new String(strbyte)).append("\r\n");   
-                        ByteBuf  data2 = data.readSlice(8);   
-                        sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                         
-                    };
-                        break;                        
-                    case 0x06: {
-                        
-                    };
-                        break;                        
-                    case 0x07: {
-                        byte[] strbyte = new byte[32];                        
-                        data.readBytes(strbyte, 0, 32);
-                        sb.append("Cpu type: ").append(new String(strbyte)).append("\r\n");                          
-                    };
-                        break;                        
-                    case 0x08: {
-                        byte[] strbyte = new byte[32];                        
-                        data.readBytes(strbyte, 0, 32);
-                        sb.append("Serial mc/mmc: ").append(new String(strbyte)).append("\r\n");                         
-                    };
-                        break;                        
-                    case 0x09: {
-                        sb.append("Manufacturer ID: ").append(data.readShort()).append("\r\n");  
-                        sb.append("Profile ID: ").append(data.readShort()).append("\r\n");   
-                        sb.append("Profile specific type: ").append(data.readShort()).append("\r\n");
-                        ByteBuf  data2 = data.readSlice(26);
-                        sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                        
-                    };
-                        break;                        
-                    case 0x0A: {
-                        byte[] strbyte = new byte[26];                        
-                        data.readBytes(strbyte, 0, 26);
-                        sb.append("OEM copyright: ").append(new String(strbyte)).append("\r\n");                        
-                        sb.append("OEM ID: ").append(data.readShort()).append("\r\n");
-                        sb.append("OEM add ID: ").append(data.readInt()).append("\r\n");
-                    };
-                        break;                        
-                    case 0x0B: {
-                        byte[] strbyte = new byte[32];                        
-                        data.readBytes(strbyte, 0, 32);
-                        sb.append("Location ID: ").append(new String(strbyte)).append("\r\n");                         
-                    };
-                        break;                        
-                    case 0x0C: {
-                        byte[] strbyte = new byte[10];                        
-                        data.readBytes(strbyte, 0, 10);
-                        sb.append("Order number sync module 1: ").append(new String(strbyte)).append("\r\n"); 
-                        data.readShort();
-                        byte[] strbyte2 = new byte[2]; 
-                        data.readBytes(strbyte2, 0, 2);
-                        sb.append("Product version: ").append(new String(strbyte2)).append("\r\n");                         
-                        data.readByte();
-                        ByteBuf  data2 = data.readSlice(17);
-                        sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                         
-                    };
-                        break;                        
-                    case 0x0D: {
-                        byte[] strbyte = new byte[10];                        
-                        data.readBytes(strbyte, 0, 10);
-                        sb.append("Order number sync module 2: ").append(new String(strbyte)).append("\r\n"); 
-                        data.readShort();
-                        byte[] strbyte2 = new byte[2]; 
-                        data.readBytes(strbyte2, 0, 2);
-                        sb.append("Product version: ").append(new String(strbyte2)).append("\r\n");                         
-                        data.readByte();
-                        ByteBuf  data2 = data.readSlice(17);                        
-                        sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                        
-                    };
-                        break;                        
-                    case 0x0E: {
-                        byte[] strbyte = new byte[18];                        
-                        data.readBytes(strbyte, 0, 18);
-                        sb.append("Serial number: ").append(new String(strbyte)).append("\r\n"); 
-                        ByteBuf  data2 = data.readSlice(14); 
-                        sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n");                         
-                    };
-                        break;                        
-                }
-                
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }        
-        return sb;
-    }      
-    
-    private static StringBuilder ID_0xXY22(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();        
-        
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");;
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");;
-
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                ByteBuf  infobytes = data.readSlice(20);
-                short al1 = data.readShort();
-                short al2 = data.readShort();
-                int al3  = data.readInt();
-                sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n");
-                sb.append("al 1: ").append(Integer.toHexString(al1)).append("\r\n");
-                sb.append("al 2: ").append(Integer.toHexString(al2)).append("\r\n");
-                sb.append("al 3: ").append(Integer.toHexString(al3)).append("\r\n");
-            }        
-        }catch (Exception ex){
-            sb.append(ex.toString());
-        }        
-        return sb;
-
-    }   
-    
-    private static StringBuilder ID_0xXY25(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    } 
-    
-    private static StringBuilder ID_0xXY32(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }     
-    
-    private static StringBuilder ID_0xXY71(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }     
-
-    private static StringBuilder ID_0xXY74(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort();
-        try {
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            for (int i=1; i <= ssl_count; i++){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                int cpu_type = data.readByte();
-                int led_id = data.readByte();
-                boolean led_onoff = (data.readByte() != 0x00);
-                int led_flashing = data.readByte();
-                
-                sb.append("Rack number: ").append((cpu_type & 0x07)).append("\r\n");
-                sb.append("CPU Type: ").append((cpu_type & 0x08) == 0x00?"Standby":"Master").append("\r\n");
-                sb.append("LED ID: ").append(LED_ID.valueOf(led_id)).append(" (").append(LED_ID.valueOf(led_id).description).append(")\r\n");
-                sb.append("LED status: ").append(led_onoff).append("\r\n");
-                switch(led_flashing){
-                    case 0x00: sb.append("LED flashing: not.").append("\r\n");
-                        break; 
-                    case 0x01: sb.append("LED blinking: normally (2 Hz).").append("\r\n");
-                        break;
-                    case 0x02: sb.append("LED blinking: slowly (0.5 Hz).").append("\r\n");
-                        break;
-                    default: sb.append("LED blinking: no information.").append("\r\n");
-                }
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }
-        return sb;
-    }  
-    
-    private static StringBuilder ID_0xXY75(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }      
-    
-    private static StringBuilder ID_0xXY90(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }     
-    
-    private static StringBuilder ID_0xXY91(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }   
-    
-    private static StringBuilder ID_0xXY92(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }  
-
-    private static StringBuilder ID_0xXY94(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }     
-    
-    private static StringBuilder ID_0xXY95(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }   
-    
-    private static StringBuilder ID_0xXY96(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }      
-    
-    private static StringBuilder ID_0xXY9C(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }      
-    
-    private static StringBuilder ID_0xXYA0(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        int ssl_length = data.readShort();
-        int ssl_count = data.readShort(); 
-        
-        try{
-            sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");
-            sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");
-            int i = 1;
-            while(data.isReadable()){
-                sb.append("Data Record: ").append(i).append("\r\n");
-                Short  id = data.readShort();
-  
-                sb.append("ID: ").append(id).append("\r\n");  
-                ByteBuf infobytes = data.readSlice(10);
-                sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n");
-                infobytes = data.readSlice(8);
-                sb.append("Timestamp: ").append(readDateAndTime(infobytes).toString()).append("\r\n");
-                sb.append("Desc: ").append(S7DiagnosticEventId.valueOf(id).getDescription()).append("\r\n");
-                i++;
-            }
-        } catch (Exception ex){
-            sb.append(ex.toString());
-        }        
-
-        return sb;
-    }      
-    
-    private static StringBuilder ID_0xXYB1(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }  
-
-    private static StringBuilder ID_0xXYB2(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }  
-
-    private static StringBuilder ID_0xXYB3(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }  
-
-    private static StringBuilder ID_0xXYB4(ByteBuf data){
-        StringBuilder sb = new StringBuilder();
-        sb.append("It is not implemeted yet!");
-        return sb;
-    }  
-    
-    /*
-     * Date and time of day (BCD coded).
-     *          +----------------+
-     * Byte n   | Year   0 to 99 |
-     *          +----------------+
-     * Byte n+1 | Month  1 to 12 |
-     *          +----------------+
-     * Byte n+2 | Day    1 to 31 |    
-     *          +----------------+
-     * Byte n+3 | Hour   0 to 23 |    
-     *          +----------------+  
-     * Byte n+4 | Minute 0 to 59 |  
-     *          +----------------+
-     * Byte n+5 | Second 0 to 59 |     
-     *          +----------------+
-     * Byte n+6 | ms    0 to 999 |
-     * Byte n+7 | X X X X X D O W|    
-     *          +----------------+    
-     * DOW: Day of weed (last 3 bits)
-    */
-    private static LocalDateTime readDateAndTime(ByteBuf data) {
-        //from Plc4XS7Protocol
-        int year=convertByteToBcd(data.readByte());
-        byte themonth = data.readByte();
-        int month=convertByteToBcd(themonth==0x00?0x01:themonth);
-        byte theday = data.readByte();
-        int day=convertByteToBcd(theday==0x00?0x01:theday);
-        int hour=convertByteToBcd(data.readByte());
-        int minute=convertByteToBcd(data.readByte());
-        int second=convertByteToBcd(data.readByte());        
-        int milliseconds = (data.readShort() & 0xfff0) >> 4;
-        
-        int cen = ((milliseconds & 0x0f00) >> 8) * 100;
-        int dec = ((milliseconds & 0x00f0) >> 4) * 10;
-        milliseconds = cen + dec + (milliseconds & 0x000f);
-        int nanoseconds = milliseconds * 1000000;
-        
-        //data-type ranges from 1990 up to 2089
-        if(year>=90){
-            year+=1900;
-        }
-        else{
-            year+=2000;
-        }
-        
-        return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds);
-    }    
-    
-   /**
-     * converts incoming byte to an integer regarding used BCD format
-     * @param incomingByte
-     * @return converted BCD number
-     */
-    private static int convertByteToBcd(byte incomingByte) {
-        int dec = (incomingByte >> 4) * 10;
-        return dec + (incomingByte & 0x0f);
-    }  
-    
-   /**
-     * converts incoming Short to an integer regarding used BCD format
-     * @param incomingShort
-     * @return converted BCD number
-     */
-    private static short convertShortToBcd(short incomingShort) {
-        
-        short res =(short)  ((incomingShort >> 8) * 100 +
-                            (incomingShort >> 4) * 10 +
-                            (incomingShort & 0x0f));
-        return res;
-    }      
-        
- }
-    
-    /*
-    *
-    */
-    public static Duration S5TimeToDuration(Short data) {
-        Duration res;
-        short t = data;
-        long tv = (short)(((t & 0x000F))+((t & 0x00F0)>>4)*10+((t & 0x0F00) >> 8)*100);       
-        long tb = (short)(10*Math.pow(10,((t & 0xF000) >> 12)));
-        long totalms = tv*tb;
-        if (totalms <= 9990000 ){
-            res = Duration.ofMillis(totalms);
-        } else {
-            res = Duration.ofMillis(9990000);
-        }            
-        return res;
-    }
-    
-    /*
-    * 
-    */
-    public static Short DurationToS5Time(Duration data) {
-        short tv = 0;
-        short tb = 0x0000_0000;
-        short s5time = 0x0000;
-        long totalms = data.toMillis();
-        
-        if ((totalms >= 0) && (totalms <= 9990000)) {
-            
-            if ((totalms>=0) && ((totalms<=9990))){
-                tb = 0x0000_0000; //10 ms
-                tv = (short)(totalms / 10);                
-            } else  if ((totalms>9990) && ((totalms<=99900))){                 
-                tb = 0x0000_0001;// 100 ms
-                tv = (short)(totalms / 100);
-            } else if ((totalms>99900) && ((totalms<=999000))){
-                tb = 0x0000_0002;//1000 ms
-                tv = (short)(totalms / 1000);                
-            } else if ((totalms>999000) && ((totalms<=9990000))){
-                tb = 0x0000_0003;//10000 ms
-                tv = (short)(totalms / 10000);                
-            }            
-           
-            short uni = (short)(tv % 10);
-            short dec = (short)((tv / 10) % 10);
-            short cen = (short)((tv / 100) % 10);
-
-            s5time = (short)(((tb)<<12) | (cen << 8) | (dec << 4) | (uni));
-        }
-        return s5time;
-    }   
-
-    public static Duration S7TimeToDuration(Integer data) {
-        Duration res = Duration.ZERO;
-        if (data>= 0){
-            res = res.plusMillis((long) data);
-        } else {
-            long ms = 0x8000_0000  - (data & 0x8000_0000);
-            res = res.minusMillis((long) data);
-        }
-        
-        return res;
-    }  
-    
-    public static Integer DurationToS7Time(Duration data) {
-        Integer res = 0x0000_0000;
-        if (data.isNegative()){
-            res = (int) data.toMillis() + 0x8000_0000;
-        } else {
-            res = (int) data.toMillis();            
-        }
-        return res;
-    } 
-
-    public static LocalTime S7TodToLocalTime(Integer data) {
-        if (data > 0x0526_5bff) data=0x0526_5bff;
-        if (data < 0) data=0x0000_0000;
-        LocalTime res = LocalTime.MIDNIGHT.plusNanos((long)data*1_000_000);
-        return res;
-    }  
-
-    public static Integer LocalTimeToS7Tod(LocalTime data) {        
-        return (int)(data.toNanoOfDay() / 1_000_000);
-    }
-    
-    public static LocalDate S7DateToLocalDate(Short data) {
-        LocalDate res = LocalDate.of(1990, 1, 1);
-        res = res.plusDays((long) data);
-        return res;
-    }
-    
-    public static Short LocalDateToS7Date(LocalDate data) {
-        LocalDate ini = LocalDate.of(1990, 1, 1);
-        long resl  = ChronoUnit.DAYS.between(ini, data);
-        short res = (short) resl;
-        return res;
-    }  
-    
-    /*
-     * Date and time of day (BCD coded).
-     *          +----------------+
-     * Byte n   | Year   0 to 99 |
-     *          +----------------+
-     * Byte n+1 | Month  1 to 12 |
-     *          +----------------+
-     * Byte n+2 | Day    1 to 31 |    
-     *          +----------------+
-     * Byte n+3 | Hour   0 to 23 |    
-     *          +----------------+  
-     * Byte n+4 | Minute 0 to 59 |  
-     *          +----------------+
-     * Byte n+5 | Second 0 to 59 |     
-     *          +----------------+
-     * Byte n+6 | ms    0 to 999 |
-     * Byte n+7 | X X X X X D O W|    
-     *          +----------------+    
-     * DOW: Day of weed (last 3 bits)
-    */
-    public static LocalDateTime S7DateTimeToLocalDateTime(ByteBuf data) {
-        //from Plc4XS7Protocol
-        int year=   BcdToInt(data.readByte());       
-        int month=  BcdToInt(data.readByte());
-        int day =   BcdToInt(data.readByte());
-        int hour=   BcdToInt(data.readByte());
-        int minute= BcdToInt(data.readByte());
-        int second= BcdToInt(data.readByte());   
-        int millih= BcdToInt(data.readByte()) * 10;
-        
-        int milll= (data.readByte() >> 4);
-         
-        int milliseconds = millih + milll;
-        int nanoseconds = milliseconds * 1000000;
-        //At this point a dont need the day of week
-        //data-type ranges from 1990 up to 2089
-        if(year>=90){
-            year+=1900;
-        }
-        else{
-            year+=2000;
-        }
-        
-        return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds);
-    }
-
-    public static LocalDateTime S7DateAndTimeToLocalDateTime(int year, int month, int day, 
-                                    int hour, int min, int sec, int msec) {
-        int nanoseconds = msec * 1000000;
-        //At this point a dont need the day of week
-        //data-type ranges from 1990 up to 2089
-        if(year>=90){
-            year+=1900;
-        }
-        else{
-            year+=2000;
-        } 
-        return LocalDateTime.of(year,month,day,hour,min,sec, nanoseconds);
-    }
-  
-    public static byte[] LocalDateTimeToS7DateTime(LocalDateTime data) {
-        byte[] res = new byte[8];
-        
-        res[0] = ByteToBcd((data.getYear() % 100));
-        res[1] = ByteToBcd(data.getMonthValue());
-        res[2] = ByteToBcd(data.getDayOfMonth());
-        res[3] = ByteToBcd(data.getHour());
-        res[4] = ByteToBcd(data.getMinute());
-        res[5] = ByteToBcd(data.getSecond());
-        
-        long ms = (long)(data.getNano() / 1_000_000);
-        res[6] = (byte)((int)(((ms / 100) << 4) | ((ms / 10)%10))) ;
-        //Java:1 (Monday) to 7 (Sunday)->S7:1 (Sunday) to 7 (Saturday)        
-        byte dayofweek = (byte)((data.getDayOfWeek().getValue()<7)?
-                                data.getDayOfWeek().getValue()+1:
-                                (byte)0x01);
-        res[7] = (byte)(((ms % 10) << 4) | ((byte)(dayofweek)));
-                
-        return res;
-    }
-   
-    
-   /**
-     * converts incoming byte to an integer regarding used BCD format
-     * @param incomingByte
-     * @return converted BCD number
-     */
-    private static byte ByteToBcd(int incomingByte) {
-        byte dec = (byte)((incomingByte / 10) % 10);
-        return (byte)((dec << 4) | (incomingByte % 10));
-    } 
-
-    private static int BcdToInt(byte bcd){
-        int res=(bcd>>4)*10 + (bcd & 0x0f);
-        return res;
-    }
-    
-    public static void ByteToBcd(final WriteBuffer buffer, short _value) throws ParseException {
-        short incomingByte = _value;
-        byte outputByte = 0;
-        byte dec = (byte)((incomingByte / 10) % 10);
-        outputByte = (byte)((dec << 4) | (incomingByte % 10));
-        buffer.writeByte(outputByte);
-    } 
-
-    public static int BcdToInt(final ReadBuffer buffer) throws ParseException{
-        byte bcd = buffer.readByte();
-        int res=(bcd>>4)*10 + (bcd & 0x0f);
-        return res;
-    } 
-    
-    public static int S7msecToInt(final ReadBuffer buffer) throws ParseException{
-        int centenas = BcdToInt(buffer.readUnsignedByte(4));
-        int decenas = BcdToInt(buffer.readUnsignedByte(4));
-        int unidad = BcdToInt(buffer.readUnsignedByte(4));
-        int res=centenas*100 + decenas*10 + unidad;
-        return res;
-    } 
-    
-    public static void IntToS7msec(final WriteBuffer buffer, int _value) throws ParseException {
-        int local = 0;
-        if (_value > 999) {
-            local = 999;
-        } else local = _value;
-        
-        int centenas = local / 100;
-        int residual = (local - centenas * 100);
-        int decenas = (residual) / 10;
-        int unidad = residual - (decenas * 10);
-        
-        buffer.writeUnsignedByte(4, (byte) centenas);
-        buffer.writeUnsignedByte(4, (byte) decenas);
-        buffer.writeUnsignedByte(4, (byte) unidad);
-    }
-
-    public static void LeftShift3(final WriteBuffer buffer, int _value) throws ParseException {
-        int valor = _value << 3;
-        buffer.writeUnsignedInt(16, valor);
-    }
-    
-    public static int RightShift3(final ReadBuffer buffer) throws ParseException {
-        return buffer.readUnsignedInt(16) >> 3;    
-    }
-    
-    //TODO: apply only if not the last item
-    public static int EventItemLength(final ReadBuffer buffer, int valueLength) {
-        int res = ((valueLength % 2 ==0) || (!buffer.hasMore((valueLength+1)*8))) ? valueLength : valueLength + 1;
-        return res;
-    }
-
-    
-    public static PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportErrorCode) {
-        if (dataTransportErrorCode == null) {
-            return PlcResponseCode.INTERNAL_ERROR;
-        }
-        switch (dataTransportErrorCode) {
-            case OK:
-                return PlcResponseCode.OK;
-            case NOT_FOUND:
-                return PlcResponseCode.NOT_FOUND;
-            case INVALID_ADDRESS:
-                return PlcResponseCode.INVALID_ADDRESS;
-            case DATA_TYPE_NOT_SUPPORTED:
-                return PlcResponseCode.INVALID_DATATYPE;
-            case ACCESS_DENIED:
-                return PlcResponseCode.ACCESS_DENIED;
-            default:
-                return PlcResponseCode.INTERNAL_ERROR;
-        }
-    }  
- 
-    
-    private static byte[] wordToBytes(long data) {
-         return new byte[]{
-         (byte) ((data >> 8) & 0xff),
-         (byte) ((data >> 0) & 0xff),
-         };
-    } 
-     
-    private static byte[] dwordToBytes(long data) {
-         return new byte[]{
-         (byte) ((data >> 24) & 0xff),
-         (byte) ((data >> 16) & 0xff),
-         (byte) ((data >> 8) & 0xff),
-         (byte) ((data >> 0) & 0xff),
-         };
-    }        
-    
-    /**
-     * 
-     */
-    public static String ModeEventProcessing(final S7ModeEvent mode){ 
-        StringBuilder sb = new StringBuilder("CPU is in : ");
-        if (ModeTransitionType.isDefined((short) mode.getMap().get("CURRENT_MODE"))){
-            short currentmode = (short) mode.getMap().get("CURRENT_MODE");
-            sb.append(ModeTransitionType.enumForValue(currentmode).name());
-        } else {
-            sb.append("UNDEFINED");
-        }
-        return sb.toString();
-    } 
-    
-    /**
-     * 
-     */
-    public static String SysEventProcessing(final S7SysEvent event, String eventtext, HashMap<String, HashMap<String, String>> textlists){
-        final Pattern EVENT_SIG =
-            Pattern.compile("(@[\\d]{0,3}[bycwixdrBYCWIXDR](%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@)");
-
-        final Pattern FIELDS =
-            Pattern.compile("@(?<sig>[\\d]{0,3})(?<type>[bycwixdrBYCWIXDR])(?<format>%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@");
-        
-        final Pattern FIELD_FORMAT =
-            Pattern.compile("%([\\d]{0,2})([duxbsDUXBS]{1})"); 
-
-        Map<String, Object> map = event.getMap();
-        Matcher matcher = EVENT_SIG.matcher(eventtext);        
-        Matcher fields = null;
-        Matcher fieldformat = null;
-        
-        String strSig = null;
-        ByteBuf bytebuf = null;
-        int length = 0;
-        int sig = 0;
-        long value = 0;
-        String strOut = new String(eventtext);
-        String strField = null;
-        
-        while (matcher.find()) {
-            fields = FIELDS.matcher(matcher.group(0));
-            if (!fields.find()) break;
-            sig = fields.group(1)==""?1:Integer.parseInt(fields.group(1));
-            if ((sig == 0) || (sig >2)) break;
-            String infofield = (sig==1)?"INFO1":"INFO2";
-            long infovalue = (long) event.getMap().get(infofield);
-            String format = fields.group(3).toUpperCase();
-            bytebuf = (sig==1)?
-                    Unpooled.wrappedBuffer(wordToBytes(infovalue)):
-                    Unpooled.wrappedBuffer(dwordToBytes(infovalue));            
-            switch(fields.group(2).toUpperCase()){
-                case "B":
-                    if (bytebuf.capacity() < Byte.BYTES) break;
-                    strField = String.valueOf(bytebuf.getBoolean(0));
-                    strOut = strOut.replaceAll(matcher.group(0), strField);
-                    ;                  
-                    break;
-                case "Y":
-                    if (bytebuf.capacity() < Byte.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedByte(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getByte(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =  bytebuf.getUnsignedByte(0);
-                        strField = Integer.toBinaryString((byte) value);
-                    } else {
-                        value = bytebuf.getByte(0);                        
-                        strField = String.format(format, value);
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                    
-                    ; 
-                    break;  
-                case "C":
-                    if (format.contains("%T#")) {
-                        
-                    } else {
-                        if (bytebuf.capacity() < Byte.BYTES) break;
-                        fieldformat = FIELD_FORMAT.matcher(format);
-                        if (fieldformat.find()) {
-                            length = Integer.parseInt(fieldformat.group(1));
-                            length = (length>bytebuf.capacity())?bytebuf.capacity():length;
-                            strField = 
-                                bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString();
-                        }
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                     
-                    ;
-                    break;   
-                case "W":
-                    if (bytebuf.capacity() < Short.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedShort(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getShort(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedShort(0);
-                        strField = Integer.toBinaryString((short) value);
-                    } else {
-                        value = bytebuf.getShort(0);                        
-                        strField = String.format(format, value);
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                      
-                    ;  
-                    break;                
-                case "I":
-                    if (bytebuf.capacity() < Integer.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getInt(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getInt(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                       
-                    ;
-                    break;                
-                case "X":
-                    if (bytebuf.capacity() < Long.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getLong(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getLong(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                      
-                    ;  
-                    break;                
-                case "D":
-                    if (bytebuf.capacity() < Double.BYTES) break;                    
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getLong(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getLong(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                     
-                    ;
-                    break;                
-                case "R":
-                    if (bytebuf.capacity() < Float.BYTES) break; 
-                    if (format.contains("F")) { 
-                        strField = String.format(format, value); 
-                        strOut = strOut.replaceAll(matcher.group(0), strField);                         
-                    }                     
-                    ;
-                    break;                    
-            }
-        }
-
-        return strOut;
-        
-    }
-    
-    /**
-     * Symbol       Meaning
-     * ======       =======
-     * @            Beginning of format string
-     * Pv           Process value number (optional)
-     * Typ          Type of process value (optional)
-     * % width      Width of the signaling field on the OP
-     * .precision   Number of decimal places (optional with format = "f")
-     * format       Process value representation mode
-     * @            End of format string
-     * 
-     * Type		Meaning
-     * ====             =======
-     * B		BOOL
-     * Y		BYTE
-     * C		CHARACTER
-     * W		WORD
-     * I		INTEGER
-     * X		DWORD
-     * D		DINT
-     * R		REAL
-     * 
-     * Representation       Format
-     * ==============       ======
-     * %[i]d                Decimal signed
-     * %[i]u                Decimal without sign
-     * %[i]x                Hexadecimal
-     * %[i].[y]f            Signed fixed point
-     * %[i]b                Binary
-     * %[i]s                Character string (STRING ANSI)
-     * %t#<Library name>    Access to text library
-     * 
-     * General representation:
-     * @@<Associated Value><Type><Format><Library name>@
-     * 
-     * @param alarm Alarm type from PLC.
-     * @param alarmtext The text string to be processed.
-     * @param textlists List of texts for indexed replacement.
-     * @return The text string with the replacement values.
-     */
-    public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmtext, HashMap<String, HashMap<String, String>> textlists){
-        final Pattern ALARM_SIG =
-            Pattern.compile("(@[\\d]{0,3}[bycwixdrBYCWIXDR](%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@)");
-
-        final Pattern FIELDS =
-            Pattern.compile("@(?<sig>[\\d]{0,3})(?<type>[bycwixdrBYCWIXDR])(?<format>%([\\d]{0,2}[duxbs]){1}|(\\d\\.\\df){1}|(t#[a-zA-Z0-9]+){1})@");
-        
-        final Pattern FIELD_FORMAT =
-            Pattern.compile("%([\\d]{0,2})([duxbsDUXBS]{1})");
-        
-        Map<String, Object> map = alarm.getMap();
-        Matcher matcher = ALARM_SIG.matcher(alarmtext);        
-        Matcher fields = null;
-        Matcher fieldformat = null;
-        
-        String strSig = null;
-        ByteBuf bytebuf = null;
-        int length = 0;
-        int sig = 0;
-        long value = 0;
-        String strOut = new String(alarmtext);
-        String strField = null;
-        
-        while (matcher.find()) {
-            fields = FIELDS.matcher(matcher.group(0));
-            if (!fields.find()) break;
-            sig = fields.group(1)==""?1:Integer.parseInt(fields.group(1));
-            strSig = "SIG_" + sig + "_DATA";
-            if ((((short) map.get("ASSOCIATED_VALUES")) == 0) ||
-                (sig > ((short) map.get("ASSOCIATED_VALUES")))) break;
-            bytebuf = Unpooled.wrappedBuffer((byte[]) map.get(strSig));
-            String format = fields.group(3).toUpperCase();
-            switch(fields.group(2).toUpperCase()){
-                case "B":
-                    if (bytebuf.capacity() < Byte.BYTES) break;
-                    strField = String.valueOf(bytebuf.getBoolean(0));
-                    strOut = strOut.replaceAll(matcher.group(0), strField);
-                    ;
-                    break;
-                case "Y":
-                    if (bytebuf.capacity() < Byte.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedByte(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getByte(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =  bytebuf.getUnsignedByte(0);
-                        strField = Integer.toBinaryString((byte) value);
-                    } else {
-                        value = bytebuf.getByte(0);                        
-                        strField = String.format(format, value);
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                    
-                    ; 
-                    break;                
-                case "C":
-                    if (format.contains("%T#")) {
-                        
-                    } else {
-                        if (bytebuf.capacity() < Byte.BYTES) break;
-                        fieldformat = FIELD_FORMAT.matcher(format);
-                        if (fieldformat.find()) {
-                            length = Integer.parseInt(fieldformat.group(1));
-                            length = (length>bytebuf.capacity())?bytebuf.capacity():length;
-                            strField = 
-                                bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString();
-                        }
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                     
-                    ;
-                    break;                
-                case "W":
-                    if (bytebuf.capacity() < Short.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedShort(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getShort(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedShort(0);
-                        strField = Integer.toBinaryString((short) value);
-                    } else {
-                        value = bytebuf.getShort(0);                        
-                        strField = String.format(format, value);
-                    }
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                      
-                    ;  
-                    break;                
-                case "I":
-                    if (bytebuf.capacity() < Integer.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getInt(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getInt(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                       
-                    ;
-                    break;                
-                case "X":
-                    if (bytebuf.capacity() < Long.BYTES) break;
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getLong(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getLong(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                      
-                    ;  
-                    break;                
-                case "D":
-                    if (bytebuf.capacity() < Double.BYTES) break;                    
-                    if (format.contains("U")) {                    
-                        value = bytebuf.getUnsignedInt(0);
-                        String strReplace = format.replace("U", "d");
-                        strField = String.format(strReplace, value);
-                    } else if (format.contains("D")){
-                        value = bytebuf.getLong(0);
-                        strField = String.format(format, value);                        
-                    } else if (format.contains("B")) {
-                        value =   bytebuf.getUnsignedInt(0);
-                        strField = Long.toBinaryString(value);
-                    } else {
-                        value = bytebuf.getLong(0);                        
-                        strField = String.format(format, value);
-                    };
-                    strOut = strOut.replaceAll(matcher.group(0), strField);                     
-                    ;
-                    break;                
-                case "R":
-                    if (bytebuf.capacity() < Float.BYTES) break; 
-                    if (format.contains("F")) { 
-                        strField = String.format(format, value); 
-                        strOut = strOut.replaceAll(matcher.group(0), strField);                         
-                    }                     
-                    ;
-                    break;
-                 
-            }
-        }
-
-        return strOut;
-    }    
-    
-     
-    
-    
-}
\ No newline at end of file
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
deleted file mode 100644
index bc0931a..0000000
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.s7.utils;
-
-import java.nio.charset.Charset;
-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;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.temporal.ChronoUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class StaticHelper {
-
-    public static LocalTime parseTiaTime(ReadBuffer io) {
-        try {
-            int millisSinceMidnight = io.readInt(32);
-            return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
-                millisSinceMidnight, ChronoUnit.MILLIS);
-        } catch (ParseException e) {
-            return null;
-        }
-    }
-
-    public static void serializeTiaTime(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing TIME not implemented");
-    }
-
-    public static LocalTime parseS5Time(ReadBuffer io) {
-        try {
-            int stuff = io.readInt(16);
-            // TODO: Implement this correctly.
-            throw new NotImplementedException("S5TIME not implemented");
-        } catch (ParseException e) {
-            return null;
-        }
-    }
-
-    public static void serializeS5Time(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing S5TIME not implemented");
-
-    }
-
-    public static LocalTime parseTiaLTime(ReadBuffer io) {
-        throw new NotImplementedException("LTIME not implemented");
-    }
-
-    public static void serializeTiaLTime(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing LTIME not implemented");
-    }
-
-    public static LocalTime parseTiaTimeOfDay(ReadBuffer io) {
-        try {
-            long millisSinceMidnight = io.readUnsignedLong(32);
-            return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(
-                millisSinceMidnight, ChronoUnit.MILLIS);
-        } catch (ParseException e) {
-            return null;
-        }
-    }
-
-    public static void serializeTiaTimeOfDay(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing TIME_OF_DAY not implemented");
-    }
-
-    public static LocalDate parseTiaDate(ReadBuffer io) {
-        try {
-            int daysSince1990 = io.readUnsignedInt(16);
-            return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS);
-        } catch (ParseException e) {
-            return null;
-        }
-    }
-
-    public static void serializeTiaDate(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing DATE not implemented");
-    }
-
-    //TODO: Call BCD converter
-    public static LocalDateTime parseTiaDateTime(ReadBuffer io) {
-        try {
-            int year = io.readUnsignedInt(16);
-            int month = io.readUnsignedInt(8);
-            int day = io.readUnsignedInt(8);
-            // Skip day-of-week
-            io.readByte();
-            int hour = io.readByte();
-            int minute = io.readByte();
-            int second = io.readByte();
-            int nanosecond = io.readUnsignedInt(24);
-            // Skip day-of-week
-            io.readByte();
-
-            return LocalDateTime.of(year, month, day, hour, minute, second, nanosecond);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    public static void serializeTiaDateTime(WriteBuffer io, PlcValue value) {
-        throw new NotImplementedException("Serializing DATE_AND_TIME not implemented");
-    }
-
-    public static String parseS7Char(ReadBuffer io, String encoding) {
-        if ("UTF-8".equalsIgnoreCase(encoding)) {
-            return io.readString(8, encoding);
-        } else if ("UTF-16".equalsIgnoreCase(encoding)) {
-            return io.readString(16, encoding);
-        } else {
-            throw new PlcRuntimeException("Unsupported encoding");
-        }
-    }
-
-    public static String parseS7String(ReadBuffer io, int stringLength, String encoding) {
-        try {
-            if ("UTF-8".equalsIgnoreCase(encoding)) {
-                // 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.readUnsignedShort(8);
-
-                final byte[] byteArray = new byte[totalStringLength];
-                for (int i = 0; (i < stringLength) && io.hasMore(8); i++) {
-                    final byte curByte = io.readByte();
-                    if (i < totalStringLength) {
-                        byteArray[i] = curByte;
-                    } else {
-                        // Gobble up the remaining data, which is not added to the string.
-                        i++;
-                        for (; (i < stringLength) && io.hasMore(8); i++) {
-                            io.readByte();
-                        }
-                        break;
-                    }
-                }
-                return new String(byteArray, StandardCharsets.UTF_8);
-            } else if ("UTF-16".equalsIgnoreCase(encoding)) {
-                // This is the maximum number of bytes a string can be long.
-                int maxLength = io.readUnsignedInt(16);
-                // This is the total length of the string on the PLC (Not necessarily the number of characters read)
-                int totalStringLength = io.readUnsignedInt(16);
-
-                final byte[] byteArray = new byte[totalStringLength * 2];
-                for (int i = 0; (i < stringLength) && io.hasMore(16); i++) {
-                    final short curShort = io.readShort(16);
-                    if (i < totalStringLength) {
-                        byteArray[i * 2] = (byte) (curShort >>> 8);
-                        byteArray[(i * 2) + 1] = (byte) (curShort & 0xFF);
-                    } else {
-                        // Gobble up the remaining data, which is not added to the string.
-                        i++;
-                        for (; (i < stringLength) && io.hasMore(16); i++) {
-                            io.readShort(16);
-                        }
-                        break;
-                    }
-                }
-                return new String(byteArray, StandardCharsets.UTF_16);
-            } else {
-                throw new PlcRuntimeException("Unsupported string encoding " + encoding);
-            }
-        } catch (ParseException e) {
-            throw new PlcRuntimeException("Error parsing string", e);
-        }
-    }
-
-    /*
-    * A variable of data type CHAR (character) occupies one byte.
-    */
-    
-    public static void serializeS7Char(WriteBuffer io, PlcValue value, String encoding) {
-        // TODO: Need to implement the serialization or we can't write strings
-        if ("UTF-8".equalsIgnoreCase(encoding)) {
-            //return io.readString(8, encoding);
-        } else if ("UTF-16".equalsIgnoreCase(encoding)) {
-            //return io.readString(16, encoding);
-        } else {
-            throw new PlcRuntimeException("Unsupported encoding");
-        }
-    }
-
-    /*           +-------------------+
-    * Byte n     | Maximum length    | (k)
-    *            +-------------------+   
-    * Byte n+1   | Current Length    | (m)
-    *            +-------------------+   
-    * Byte n+2   | 1st character     | \         \
-    *            +-------------------+  |         |
-    * Byte n+3   | 2st character     |  | Current |
-    *            +-------------------+   >        |
-    * Byte ...   | ...               |  | length  |  Maximum
-    *            +-------------------+  |          >
-    * Byte n+m+1 | mth character     | /          |  length
-    *            +-------------------+            |
-    * Byte ...   | ...               |            |
-    *            +-------------------+            |
-    * Byte ...   | ...               |           /
-    *            +-------------------+    
-    * For this version, the user must read the maximum acceptable length in
-    * the string in a first instance.
-    * Then the user application should avoid the envelope of the adjacent 
-    * fields passing the maximum length in "stringLength".
-    * If your application does not handle S7string, you can handle 
-    * the String as char arrays from your application.
-    */
-    public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, String encoding) {
-        byte k = (byte) ((stringLength > 250)?250:stringLength);
-        byte m = (byte) value.getString().length();
-        m = (m > k)?k:m;    
-        byte[] chars = new byte[m];
-        for (int i = 0; i < m; ++i) {
-             char c = value.getString().charAt(i);
-             chars[i]= (byte) c;
-          }   
-        
-        try {
-            io.writeByte(k);
-            io.writeByte(m); 
-            io.writeByteArray(chars); 
-        } catch (ParseException ex) {
-            Logger.getLogger(StaticHelper.class.getName()).log(Level.SEVERE, null, ex);
-        }
-    }
-
-}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
index 449ca79..1548b4b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
@@ -18,7 +18,7 @@
  */
 package org.apache.plc4x.java.spi.codegen;
 
-import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.codegen.io.ByteOrderAware;
 import org.apache.plc4x.java.spi.generation.*;
 
 import java.util.Objects;
@@ -44,18 +44,18 @@ public interface FieldCommons {
         return Optional.empty();
     }
 
-    default <T> T switchByteOrderIfNecessary(RunWrapped<T> runnable, DataReader<T> dataReader, ByteOrder wantedByteOrder) throws ParseException {
+    default <T> T switchByteOrderIfNecessary(RunWrapped<T> runnable, ByteOrderAware byteOrderAware, ByteOrder wantedByteOrder) throws ParseException {
         Objects.requireNonNull(runnable);
-        Objects.requireNonNull(dataReader);
-        ByteOrder currentByteOrder = dataReader.getByteOrder();
+        Objects.requireNonNull(byteOrderAware);
+        ByteOrder currentByteOrder = byteOrderAware.getByteOrder();
         if (wantedByteOrder == null || currentByteOrder == wantedByteOrder) {
             return runnable.run();
         }
         try {
-            dataReader.setByteOrder(wantedByteOrder);
+            byteOrderAware.setByteOrder(wantedByteOrder);
             return runnable.run();
         } finally {
-            dataReader.setByteOrder(currentByteOrder);
+            byteOrderAware.setByteOrder(currentByteOrder);
         }
     }
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
index e7bb0b8..63b9a3d 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
@@ -19,12 +19,12 @@
 package org.apache.plc4x.java.spi.codegen.fields;
 
 import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.codegen.io.ParseSupplier;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
 import java.util.List;
-import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 public class FieldReaderFactory {
@@ -93,14 +93,18 @@ public class FieldReaderFactory {
         return new FieldReaderOptional<T>().readOptionalField(logicalName, dataReader, condition, readerArgs);
     }
 
-    public static byte[] readManualByteArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, Supplier<Byte> parse, WithReaderArgs... readerArgs) throws ParseException {
+    public static byte[] readManualByteArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, ParseSupplier<Byte> parse, WithReaderArgs... readerArgs) throws ParseException {
         return new FieldReaderManualArray<Byte>().readManualByteArrayField(logicalName, readBuffer, termination, parse, readerArgs);
     }
 
-    public static <T> List<T> readManualArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, Supplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
+    public static <T> List<T> readManualArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, ParseSupplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
         return new FieldReaderManualArray<T>().readManualArrayField(logicalName, readBuffer, termination, parse, readerArgs);
     }
 
+    public static <T> T readManualField(String logicalName, ReadBuffer readBuffer, ParseSupplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
+        return new FieldReaderManual<T>().readManualField(logicalName, readBuffer, parse, readerArgs);
+    }
+
     public static <T> void readPaddingField(DataReader<T> dataReader, int timesPadding, WithReaderArgs... readerArgs) throws ParseException {
         new FieldReaderPadding<T>().readPaddingField(dataReader, timesPadding, readerArgs);
     }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java
index e355007..95e9a96 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java
@@ -19,13 +19,13 @@
 package org.apache.plc4x.java.spi.codegen.fields;
 
 import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.codegen.io.ParseSupplier;
 import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.function.Function;
-
 public class FieldReaderManual<T> implements FieldReader<T> {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderManual.class);
@@ -35,8 +35,11 @@ public class FieldReaderManual<T> implements FieldReader<T> {
         throw new IllegalStateException("not possible with checksum field");
     }
 
-    public T readField(String logicalName, DataReader<T> dataReader, Function parseFunction, Function serializeFunction, Function lengthFunction, WithReaderArgs... readerArgs) throws ParseException {
-        return switchByteOrderIfNecessary(() -> dataReader.read(logicalName, readerArgs), dataReader, extractByteOder(readerArgs).orElse(null));
+    public T readManualField(String logicalName, ReadBuffer readBuffer, ParseSupplier<T> parseFunction, WithReaderArgs... readerArgs) throws ParseException {
+        readBuffer.pullContext(logicalName);
+        T value = switchByteOrderIfNecessary(parseFunction::get, readBuffer, extractByteOder(readerArgs).orElse(null));
+        readBuffer.closeContext(logicalName);
+        return value;
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java
index 49ceccf..952fefb 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.spi.codegen.fields;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.codegen.io.ParseSupplier;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
@@ -41,7 +42,7 @@ public class FieldReaderManualArray<T> implements FieldReader<T> {
         throw new NotImplementedException();
     }
 
-    public byte[] readManualByteArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, Supplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
+    public byte[] readManualByteArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, ParseSupplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
         // Ensure we have the render as list argument present
         readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
         readBuffer.pullContext(logicalName, readerArgs);
@@ -53,7 +54,7 @@ public class FieldReaderManualArray<T> implements FieldReader<T> {
         return ArrayUtils.toPrimitive(result.toArray(new Byte[0]));
     }
 
-    public List<T> readManualArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, Supplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
+    public List<T> readManualArrayField(String logicalName, ReadBuffer readBuffer, Supplier<Boolean> termination, ParseSupplier<T> parse, WithReaderArgs... readerArgs) throws ParseException {
         // Ensure we have the render as list argument present
         readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
         readBuffer.pullContext(logicalName, readerArgs);
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ByteOrderAware.java
similarity index 73%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ByteOrderAware.java
index 402b9dc..621c37f 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ByteOrderAware.java
@@ -16,19 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.profinet.utils;
+package org.apache.plc4x.java.spi.codegen.io;
 
-public class StaticHelper {
+import org.apache.plc4x.java.spi.generation.ByteOrder;
 
-    public static int stringLength(String str) {
-        if (str == null) {
-            return 0;
-        }
-        return str.length();
-    }
-
-    public static int arrayLength(byte[] arr) {
-        return arr.length;
-    }
+public interface ByteOrderAware {
+    ByteOrder getByteOrder();
 
+    void setByteOrder(ByteOrder byteOrder);
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java
index aa3b482..f6871b3 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java
@@ -18,11 +18,10 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
-import org.apache.plc4x.java.spi.generation.ByteOrder;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
-public interface DataReader<T> {
+public interface DataReader<T> extends ByteOrderAware{
 
     T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException;
 
@@ -30,10 +29,6 @@ public interface DataReader<T> {
 
     void setPos(int position);
 
-    ByteOrder getByteOrder();
-
-    void setByteOrder(ByteOrder byteOrder);
-
     void pullContext(String logicalName, WithReaderArgs... readerArgs);
     void closeContext(String logicalName, WithReaderArgs... readerArgs);
 
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
index eb1bf63..095b6e0 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderFactory.java
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.spi.codegen.io;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
 
 import java.math.BigInteger;
+import java.util.function.Function;
 
 public class DataReaderFactory {
 
@@ -84,4 +85,8 @@ public class DataReaderFactory {
         return new DataReaderSimpleString(readBuffer, bitLength);
     }
 
+    public static <T, I> DataReaderEnumDefault<T, I> readEnum(Function<I, T> enumResolver, DataReader<I> dataReader) {
+        return new DataReaderEnumDefault<>(enumResolver, dataReader);
+    }
+
 }
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ParseSupplier.java
similarity index 73%
rename from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
rename to plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ParseSupplier.java
index 402b9dc..6254cfa 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/ParseSupplier.java
@@ -16,19 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.profinet.utils;
+package org.apache.plc4x.java.spi.codegen.io;
 
-public class StaticHelper {
+import org.apache.plc4x.java.spi.generation.ParseException;
 
-    public static int stringLength(String str) {
-        if (str == null) {
-            return 0;
-        }
-        return str.length();
-    }
+@FunctionalInterface
+public interface ParseSupplier<T> {
 
-    public static int arrayLength(byte[] arr) {
-        return arr.length;
-    }
+    T get() throws ParseException;
 
 }
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 9032e6b..5bc4246 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
@@ -18,20 +18,18 @@
  */
 package org.apache.plc4x.java.spi.generation;
 
+import org.apache.plc4x.java.spi.codegen.io.ByteOrderAware;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
-public interface ReadBuffer {
+public interface ReadBuffer extends ByteOrderAware {
     int getPos();
 
     void reset(int pos);
 
     boolean hasMore(int numBits);
 
-    ByteOrder getByteOrder();
-
-    void setByteOrder(ByteOrder byteOrder);
-
     void pullContext(String logicalName, WithReaderArgs... readerArgs);
 
     boolean readBit(String logicalName, WithReaderArgs... readerArgs) throws ParseException;
diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/helper/HeaderParser.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java
similarity index 96%
rename from plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/helper/HeaderParser.java
rename to plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java
index 1308e59..02b04f0 100644
--- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/helper/HeaderParser.java
+++ b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.transport.socketcan.helper;
+package org.apache.plc4x.java.socketcan.readwrite.utils;
 
-public class HeaderParser {
+public class StaticHelper {
 
     public static final int EFF_FLAG = 0b10000000_00000000_00000000_00000000;
     public static final int RTR_FLAG = 0b01000000_00000000_00000000_00000000;
diff --git a/pom.xml b/pom.xml
index ae153ab..1e45fd5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -167,6 +167,8 @@
     <asciidoctor.maven.plugin.version>2.1.0</asciidoctor.maven.plugin.version>
     <asciidoctorj.version>2.5.1</asciidoctorj.version>
     <asciidoctorj.diagram.version>2.1.2</asciidoctorj.diagram.version>
+
+    <skip-code-generation-tests>false</skip-code-generation-tests>
   </properties>
 
   <modules>
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index 712e7b1..8ab13cc 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -465,11 +465,11 @@
         ]
         ['"IEC61131_STRING"' STRING
             // TODO: Fix this length
-            [manual   vstring 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' 'stringLength + 1']
+            [manual   vstring 'value' 'STATIC_CALL("parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' 'stringLength + 1']
         ]
         ['"IEC61131_WSTRING"' STRING
             // TODO: Fix this length
-            [manual vstring 'value' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.ads.utils.StaticHelper.serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' '(stringLength * 2) + 2' encoding='"UTF-16"']
+            [manual vstring 'value' 'STATIC_CALL("parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' '(stringLength * 2) + 2' encoding='"UTF-16"']
         ]
 
         // -----------------------------------------
diff --git a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
index 8e90037..ded00ac 100644
--- a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
+++ b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
@@ -109,7 +109,7 @@
         ]
         ['INITIATE_DOWNLOAD' SDOInitiateDownloadRequest
             [reserved uint 1 '0x00']
-            [implicit uint 2 'size' 'STATIC_CALL("org.apache.plc4x.java.canopen.helper.CANOpenHelper.count", expedited, indicated, payload)']
+            [implicit uint 2 'size' 'STATIC_CALL("count", expedited, indicated, payload)']
             [simple bit 'expedited']
             [simple bit 'indicated']
             [simple IndexAddress 'address']
@@ -155,7 +155,7 @@
         ]
         ['INITIATE_UPLOAD' SDOInitiateUploadResponse
             [reserved uint 1 '0x00']
-            [implicit uint 2 'size' 'STATIC_CALL("org.apache.plc4x.java.canopen.helper.CANOpenHelper.count", expedited, indicated, payload)']
+            [implicit uint 2 'size' 'STATIC_CALL("count", expedited, indicated, payload)']
             [simple bit 'expedited']
             [simple bit 'indicated']
             [simple IndexAddress 'address']
diff --git a/protocols/df1/src/main/resources/protocols/df1/df1.mspec b/protocols/df1/src/main/resources/protocols/df1/df1.mspec
index 843a667..5db2b33 100644
--- a/protocols/df1/src/main/resources/protocols/df1/df1.mspec
+++ b/protocols/df1/src/main/resources/protocols/df1/df1.mspec
@@ -27,7 +27,7 @@
             [simple   DF1Command   'command']
             [const    uint 8       'messageEnd' '0x10']
             [const    uint 8       'endTransaction' '0x03']
-            [checksum uint 16      'crc' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.crcCheck", destinationAddress, sourceAddress, command)']
+            [checksum uint 16      'crc' 'STATIC_CALL("crcCheck", destinationAddress, sourceAddress, command)']
         ]
         ['0x06' DF1SymbolMessageFrameACK
         ]
@@ -46,7 +46,7 @@
             [simple uint 8     'size']
         ]
         ['0x41' DF1UnprotectedReadResponse
-            [manualArray  byte 'data' terminated 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.dataTerminate", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.readData", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.writeData", writeBuffer, element)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.dataLength", data)']
+            [manualArray  byte 'data' terminated 'STATIC_CALL("dataTerminate", readBuffer)' 'STATIC_CALL("readData", readBuffer)' 'STATIC_CALL("writeData", writeBuffer, element)' 'STATIC_CALL("dataLength", data)']
         ]
     ]
 ]
diff --git a/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec b/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
index 043c881..250483d 100644
--- a/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
+++ b/protocols/firmata/src/main/resources/protocols/firmata/firmata.mspec
@@ -115,7 +115,7 @@
         ['0x79','true' SysexCommandReportFirmwareResponse
             [simple uint 8 'majorVersion']
             [simple uint 8 'minorVersion']
-            [manualArray byte 'fileName' terminated 'STATIC_CALL("org.apache.plc4x.java.firmata.readwrite.utils.FirmataUtils.isSysexEnd", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.firmata.readwrite.utils.FirmataUtils.parseSysexString", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.firmata.readwrite.utils.FirmataUtils.serializeSysexString", writeBuffer, element)' 'STATIC_CALL("org.apache.plc4x.java.firmata.readwrite.utils.FirmataUtils.lengthSysexString", fileName)']
+            [manualArray byte 'fileName' terminated 'STATIC_CALL("isSysexEnd", readBuffer)' 'STATIC_CALL("parseSysexString", readBuffer)' 'STATIC_CALL("serializeSysexString", writeBuffer, element)' 'STATIC_CALL("lengthSysexString", fileName)']
         ]
         ['0x7A' SysexCommandSamplingInterval
         ]
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index a23c071..79f486e 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -369,13 +369,13 @@
             [reserved uint 16     '0x0000'                                              ]
             // TODO: Figure out how to do this correctly.
             [array    byte        'deviceVendorValue' count 'blockLength-2'             ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", deviceVendorValue) % 2']
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("arrayLength", deviceVendorValue) % 2']
         ]
         ['DEVICE_PROPERTIES_OPTION','2' PnDcp_Block_DevicePropertiesNameOfStation(uint 16 'blockLength')
             [reserved uint 16     '0x0000'                                              ]
             // TODO: Figure out how to do this correctly.
             [array    byte        'nameOfStation' count 'blockLength-2'                 ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", nameOfStation) % 2']
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("arrayLength", nameOfStation) % 2']
         ]
         ['DEVICE_PROPERTIES_OPTION','3' PnDcp_Block_DevicePropertiesDeviceId
             [reserved uint 16 '0x0000'                                                  ]
@@ -398,7 +398,7 @@
         ['DEVICE_PROPERTIES_OPTION','6' PnDcp_Block_DevicePropertiesAliasName(uint 16 'blockLength')
             [reserved uint 16     '0x0000'                                              ]
             [array    byte        'aliasNameValue' count 'blockLength-2'                ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", aliasNameValue) % 2']
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("arrayLength", aliasNameValue) % 2']
         ]
         ['DEVICE_PROPERTIES_OPTION','7' PnDcp_Block_DevicePropertiesDeviceInstance
             [reserved uint 16 '0x0000'                                                  ]
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index ebe12e0..008097a 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -280,19 +280,19 @@
 [type 'AssociatedValueType'
     [simple DataTransportErrorCode 'returnCode']
     [simple DataTransportSize      'transportSize']
-    [manual uint 16                'valueLength'   'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.RightShift3", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.LeftShift3", writeBuffer, _value.valueLength)' '2']
-    [array  uint 8                 'data'          count    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.EventItemLength", readBuffer, valueLength)']
+    [manual uint 16                'valueLength'   'STATIC_CALL("RightShift3", readBuffer)' 'STATIC_CALL("LeftShift3", writeBuffer, _value.valueLength)' '2']
+    [array  uint 8                 'data'          count    'STATIC_CALL("EventItemLength", readBuffer, valueLength)']
 ]
 
 //TODO: Convert BCD to uint
 [type 'DateAndTime'
-    [manual uint 8  'year'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.year)'    '1']
-    [manual uint 8  'month'   'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.month)'   '1']
-    [manual uint 8  'day'     'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.day)'     '1']
-    [manual uint 8  'hour'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.hour)'    '1']
-    [manual uint 8  'minutes' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.minutes)' '1']
-    [manual uint 8  'seconds' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.BcdToInt", readBuffer)'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.ByteToBcd", writeBuffer, _value.seconds)' '1']
-    [manual uint 12 'msec'    'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.S7msecToInt", readBuffer)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.S7EventHelper.IntToS7msec", writeBuffer, _value.msec)'  '2']
+    [manual uint 8  'year'    'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.year)'    '1']
+    [manual uint 8  'month'   'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.month)'   '1']
+    [manual uint 8  'day'     'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.day)'     '1']
+    [manual uint 8  'hour'    'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.hour)'    '1']
+    [manual uint 8  'minutes' 'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.minutes)' '1']
+    [manual uint 8  'seconds' 'STATIC_CALL("BcdToInt", readBuffer)'    'STATIC_CALL("ByteToBcd", writeBuffer, _value.seconds)' '1']
+    [manual uint 12 'msec'    'STATIC_CALL("S7msecToInt", readBuffer)' 'STATIC_CALL("IntToS7msec", writeBuffer, _value.msec)'  '2']
     [simple uint 4  'dow']
 ]
 
@@ -597,18 +597,18 @@
         // Characters & Strings
         // -----------------------------------------
         ['"IEC61131_CHAR"' CHAR
-            [manual string 8 'value'  'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7Char", readBuffer, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7Char", writeBuffer, _value, _type.encoding)' '1']
+            [manual string 8 'value'  'STATIC_CALL("parseS7Char", readBuffer, _type.encoding)' 'STATIC_CALL("serializeS7Char", writeBuffer, _value, _type.encoding)' '1']
         ]
         ['"IEC61131_WCHAR"' CHAR
-            [manual string 16 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7Char", readBuffer, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7Char", writeBuffer, _value, _type.encoding)' '2' encoding='"UTF-16"']
+            [manual string 16 'value' 'STATIC_CALL("parseS7Char", readBuffer, _type.encoding)' 'STATIC_CALL("serializeS7Char", writeBuffer, _value, _type.encoding)' '2' encoding='"UTF-16"']
         ]
         ['"IEC61131_STRING"' STRING
             // TODO: Fix this length
-            [manual vstring 'value'  'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' 'STR_LEN(_value) + 2']
+            [manual vstring 'value'  'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' 'STR_LEN(_value) + 2']
         ]
         ['"IEC61131_WSTRING"' STRING
             // TODO: Fix this length
-            [manual vstring 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' '(STR_LEN(_value) * 2) + 2' encoding='"UTF-16"']
+            [manual vstring 'value' 'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' '(STR_LEN(_value) * 2) + 2' encoding='"UTF-16"']
         ]
 
         // -----------------------------------------
diff --git a/protocols/socketcan/src/main/resources/protocols/can/socketcan.mspec b/protocols/socketcan/src/main/resources/protocols/can/socketcan.mspec
index be266e1..ba3f552 100644
--- a/protocols/socketcan/src/main/resources/protocols/can/socketcan.mspec
+++ b/protocols/socketcan/src/main/resources/protocols/can/socketcan.mspec
@@ -20,16 +20,16 @@
 [type 'SocketCANFrame' byteOrder='"LITTLE_ENDIAN"'
     [simple int 32 'rawId']
     [virtual int 32 'identifier'
-        'STATIC_CALL("org.apache.plc4x.java.transport.socketcan.helper.HeaderParser.readIdentifier", rawId)'
+        'STATIC_CALL("readIdentifier", rawId)'
     ]
     [virtual bit 'extended'
-        'STATIC_CALL("org.apache.plc4x.java.transport.socketcan.helper.HeaderParser.isExtended", rawId)'
+        'STATIC_CALL("isExtended", rawId)'
     ]
     [virtual bit 'remote'
-        'STATIC_CALL("org.apache.plc4x.java.transport.socketcan.helper.HeaderParser.isRemote", rawId)'
+        'STATIC_CALL("isRemote", rawId)'
     ]
     [virtual bit 'error'
-        'STATIC_CALL("org.apache.plc4x.java.transport.socketcan.helper.HeaderParser.isError", rawId)'
+        'STATIC_CALL("isError", rawId)'
     ]
     [implicit uint 8 'size' 'COUNT(data)']
     [reserved uint 8 '0x0'] //flags
diff --git a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/readwrite/utils/StaticHelper.java
similarity index 97%
rename from sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
rename to sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/readwrite/utils/StaticHelper.java
index 9a428a3..c03e1bb 100644
--- a/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/util/DF1Utils.java
+++ b/sandbox/test-java-df1-driver/src/main/java/org/apache/plc4x/java/df1/readwrite/utils/StaticHelper.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.plc4x.java.df1.util;
+package org.apache.plc4x.java.df1.readwrite.utils;
 
 import com.github.snksoft.crc.CRC;
 import org.apache.plc4x.java.df1.readwrite.DF1Command;
@@ -25,7 +25,7 @@ import org.apache.plc4x.java.spi.generation.*;
 
 import java.util.List;
 
-public class DF1Utils {
+public class StaticHelper {
 
     public static int crcCheck(short destinationAddress, short sourceAddress, DF1Command command) {
         // CRC-16/DF-1
diff --git a/src/site/asciidoc/developers/code-gen/protocol/df1.adoc b/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
index a598cad..3d0f89c 100644
--- a/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
+++ b/src/site/asciidoc/developers/code-gen/protocol/df1.adoc
@@ -64,7 +64,7 @@ Here is the MSpec to model the behaviour:
             [simple   DF1Command   'command']
             [const    uint 8       'messageEnd' '0x10']
             [const    uint 8       'endTransaction' '0x03']
-            [checksum uint 16      'crc' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.crcCheck", destinationAddress, sourceAddress, command)']
+            [checksum uint 16      'crc' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.crcCheck", destinationAddress, sourceAddress, command)']
         ]
         ['0x06' DF1SymbolMessageFrameACK
         ]
@@ -83,7 +83,7 @@ Here is the MSpec to model the behaviour:
             [simple uint 8     'size']
         ]
         ['0x41' DF1UnprotectedReadResponse
-            [manualArray  uint 8 'data' terminated 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.dataTerminate", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.readData", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.writeData", io, element)' 'STATIC_CALL("org.apache.plc4x.java.df1.util.DF1Utils.dataLength", data)']
+            [manualArray  uint 8 'data' terminated 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.dataTerminate", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.readData", io)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.writeData", io, element)' 'STATIC_CALL("org.apache.plc4x.java.df1.readwrite.utils.StaticHelper.dataLength", data)']
         ]
     ]
 ]