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/12/15 21:24:35 UTC

[plc4x] 01/09: - Work on PLC4net - Work on C# code generation

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

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

commit c88b01d668cc5b156701b155a1501972165fb1f9
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Dec 2 18:51:47 2020 +0100

    - Work on PLC4net
    - Work on C# code generation
---
 .../plc4net => build-utils/language-cs}/pom.xml    |   48 +-
 .../apache/plc4x/language/cs/CsLanguageOutput.java |   72 +
 .../language/cs/CsLanguageTemplateHelper.java      | 1053 ++++++
 ...x.plugins.codegenerator.language.LanguageOutput |   19 +
 .../resources/templates/cs/data-io-template.ftlh   |  206 +
 sandbox/plc4net/.gitignore                         |    7 +-
 .../{ => api}/exceptions/PlcConnectionException.cs |    0
 .../api/{ => api}/exceptions/PlcException.cs       |    0
 .../exceptions/PlcInvalidFieldException.cs         |    0
 .../api/{ => api}/messages/IPlcFieldRequest.cs     |    0
 .../api/{ => api}/messages/IPlcFieldResponse.cs    |    0
 .../plc4net/api/{ => api}/messages/IPlcMessage.cs  |    0
 .../api/{ => api}/messages/IPlcReadRequest.cs      |    0
 .../{ => api}/messages/IPlcReadRequestBuilder.cs   |    0
 .../api/{ => api}/messages/IPlcReadResponse.cs     |    0
 .../plc4net/api/{ => api}/messages/IPlcRequest.cs  |    0
 .../api/{ => api}/messages/IPlcRequestBuilder.cs   |    0
 .../plc4net/api/{ => api}/messages/IPlcResponse.cs |    0
 .../messages/IPlcSubscriptionEventArgs.cs          |    0
 .../{ => api}/messages/IPlcSubscriptionRequest.cs  |    0
 .../messages/IPlcSubscriptionRequestBuilder.cs     |    0
 .../{ => api}/messages/IPlcSubscriptionResponse.cs |    0
 .../messages/IPlcUnsubscriptionRequest.cs          |    0
 .../messages/IPlcUnsubscriptionRequestBuilder.cs   |    0
 .../messages/IPlcUnsubscriptionResponse.cs         |    0
 .../api/{ => api}/messages/IPlcWriteRequest.cs     |    0
 .../{ => api}/messages/IPlcWriteRequestBuilder.cs  |    0
 sandbox/plc4net/api/{ => api}/model/IPlcField.cs   |    0
 .../api/{ => api}/model/IPlcSubscriptionHandle.cs  |    0
 .../plc4net/api/{ => api}/types/PlcResponseCode.cs |    0
 sandbox/plc4net/api/api/value/IPlcValue.cs         |   68 +
 .../plc4net/api/{api.csproj => plc4net-api.csproj} |   14 +-
 .../knxnetip/readwrite/model/KnxDatapoint.cs       | 3955 ++++++++++++++++++++
 .../knxnetip/ParserSerializerTestsuite.xml         |  500 +++
 .../knxnetip/plc4net-driver-knxproj.csproj}        |   11 +-
 sandbox/plc4net/plc4net.sln                        |   34 +-
 sandbox/plc4net/pom.xml                            |  102 +-
 .../{api/api.csproj => spi/plc4net-spi.csproj}     |   22 +-
 sandbox/plc4net/spi/spi/generation/ReadBuffer.cs   |  203 +
 sandbox/plc4net/spi/spi/generation/WriteBuffer.cs  |   89 +
 sandbox/plc4net/spi/spi/model/values/PlcBOOL.cs    |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcBYTE.cs    |   32 +
 .../plc4net/spi/spi/model/values/PlcBitString.cs   |    7 +
 sandbox/plc4net/spi/spi/model/values/PlcCHAR.cs    |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcDATE.cs    |   34 +
 .../spi/spi/model/values/PlcDATE_AND_TIME.cs       |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcDINT.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcDWORD.cs   |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcINT.cs     |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcLINT.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcLREAL.cs   |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcLTIME.cs   |   34 +
 sandbox/plc4net/spi/spi/model/values/PlcLWORD.cs   |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcNULL.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcPlcList.cs |   34 +
 sandbox/plc4net/spi/spi/model/values/PlcREAL.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcSINT.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcSTRING.cs  |   33 +
 .../model/values/PlcSimpleNumericValueAdapter.cs   |  175 +
 .../spi/spi/model/values/PlcSimpleValueAdapter.cs  |   17 +
 sandbox/plc4net/spi/spi/model/values/PlcStruct.cs  |   37 +
 .../spi/spi/model/values/PlcTIME _OF_DAY.cs        |   34 +
 sandbox/plc4net/spi/spi/model/values/PlcTIME.cs    |   34 +
 sandbox/plc4net/spi/spi/model/values/PlcUDINT.cs   |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcUINT.cs    |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcULINT.cs   |   30 +
 sandbox/plc4net/spi/spi/model/values/PlcUSINT.cs   |   30 +
 .../spi/spi/model/values/PlcValueAdapter.cs        |  223 ++
 sandbox/plc4net/spi/spi/model/values/PlcWCHAR.cs   |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcWORD.cs    |   33 +
 sandbox/plc4net/spi/spi/model/values/PlcWSTRING.cs |   33 +
 71 files changed, 7644 insertions(+), 47 deletions(-)

diff --git a/sandbox/plc4net/pom.xml b/build-utils/language-cs/pom.xml
similarity index 52%
copy from sandbox/plc4net/pom.xml
copy to build-utils/language-cs/pom.xml
index ab7bdb8..2a02405 100644
--- a/sandbox/plc4net/pom.xml
+++ b/build-utils/language-cs/pom.xml
@@ -22,25 +22,37 @@
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
-    <groupId>org.apache.plc4x.sandbox</groupId>
-    <artifactId>plc4x-sandbox</artifactId>
-    <version>0.10.0-SNAPSHOT</version>
+    <groupId>org.apache.plc4x</groupId>
+    <artifactId>plc4x-build-utils</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>plc4net</artifactId>
-  <packaging>pom</packaging>
-
-  <name>Sandbox: PLC4Net</name>
-  <description>Implementation of the protocol adapters for usage as .Net module.</description>
-
-  <!-- Disabled for now as C# support is currently not installed in Apache SonarQube -->
-  <!--properties>
-    <sonar.language>c#</sonar.language>
-  </properties-->
-
-  <modules>
-    <module>api</module>
-    <module>plc4net.driver</module>
-  </modules>
+  <artifactId>plc4x-build-utils-language-cs</artifactId>
+
+  <name>PLC4X: Build Utils: Language: C#</name>
+  <description>Code generation template for generating C# code</description>
+
+  <dependencies>
+    <!-- We are using the Freemarker module to generate Java code -->
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-build-utils-language-base-freemarker</artifactId>
+      <version>0.8.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x.plugins</groupId>
+      <artifactId>plc4x-code-generation-types-base</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.freemarker</groupId>
+      <artifactId>freemarker</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-text</artifactId>
+    </dependency>
+  </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java b/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
new file mode 100644
index 0000000..fc5a489
--- /dev/null
+++ b/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageOutput.java
@@ -0,0 +1,72 @@
+/*
+ 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.language.cs;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageOutput;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class CsLanguageOutput extends FreemarkerLanguageOutput {
+
+    @Override
+    public String getName() {
+        return "C#";
+    }
+
+    @Override
+    public List<String> supportedOutputFlavors() {
+        return Arrays.asList("read-write", "read-only", "passive");
+    }
+
+    @Override
+    protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected List<Template> getComplexTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected List<Template> getEnumTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected List<Template> getDataIoTemplates(Configuration freemarkerConfiguration) throws IOException {
+        return Collections.singletonList(
+            freemarkerConfiguration.getTemplate("templates/cs/data-io-template.ftlh"));
+    }
+
+    @Override
+    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
+        return new CsLanguageTemplateHelper(thisType, protocolName, flavorName, types);
+    }
+
+}
diff --git a/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java b/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
new file mode 100644
index 0000000..223654d
--- /dev/null
+++ b/build-utils/language-cs/src/main/java/org/apache/plc4x/language/cs/CsLanguageTemplateHelper.java
@@ -0,0 +1,1053 @@
+/*
+ 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.language.cs;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
+import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
+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 java.util.*;
+
+@SuppressWarnings({"unused", "WeakerAccess"})
+public class CsLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
+
+    public CsLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
+        super(thisType, protocolName, flavorName, types);
+    }
+
+    public String fileName(String protocolName, String languageName, String languageFlavorName) {
+        return String.join("", protocolName.split("\\-")) + "." +
+            String.join("", languageFlavorName.split("\\-"));
+    }
+
+    public String packageName(String languageFlavorName) {
+        return String.join("", languageFlavorName.split("\\-"));
+    }
+
+    @Override
+    public String getLanguageTypeNameForField(Field field) {
+        boolean optional = field instanceof OptionalField;
+        // If the referenced type is a DataIo type, the value is of type PlcValue.
+        if(field instanceof PropertyField) {
+            PropertyField propertyField = (PropertyField) field;
+            if(propertyField.getType() instanceof ComplexTypeReference) {
+                ComplexTypeReference complexTypeReference = (ComplexTypeReference) propertyField.getType();
+                final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
+                if(typeDefinition instanceof DataIoTypeDefinition) {
+                    return "PlcValue";
+                }
+            }
+        }
+        return getLanguageTypeNameForTypeReference(((TypedField) field).getType());
+    }
+
+    @Override
+    public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
+        if(typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case BIT: {
+                    return "bool";
+                }
+                case UINT: {
+                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (integerTypeReference.getSizeInBits() <= 8) {
+                        return "byte";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 16) {
+                        return "ushort";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 32) {
+                        return "uint";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 64) {
+                        return "ulong";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case INT: {
+                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (integerTypeReference.getSizeInBits() <= 8) {
+                        return "sbyte";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 16) {
+                        return "short";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 32) {
+                        return "int";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 64) {
+                        return "long";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case FLOAT:
+                case UFLOAT: {
+                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                    int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
+                        floatTypeReference.getExponent() + floatTypeReference.getMantissa();
+                    if (sizeInBits <= 32) {
+                        return "float";
+                    }
+                    if (sizeInBits <= 64) {
+                        return "double";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case STRING: {
+                    return "string";
+                }
+                case TIME: {
+                    return "time";
+                }
+                case DATE: {
+                    return "date";
+                }
+                case DATETIME: {
+                    return "datetime2";
+                }
+            }
+            throw new RuntimeException("Unsupported simple type");
+        } else {
+            return (typeReference != null) ? ((ComplexTypeReference) typeReference).getName() : "";
+        }
+    }
+
+    public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
+        if(typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case BIT: {
+                    return "PlcBOOL";
+                }
+                case UINT: {
+                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (integerTypeReference.getSizeInBits() <= 8) {
+                        return "PlcUSINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 16) {
+                        return "PlcUINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 32) {
+                        return "PlcUDINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 64) {
+                        return "PlcULINT";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case INT: {
+                    IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                    if (integerTypeReference.getSizeInBits() <= 8) {
+                        return "PlcSINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 16) {
+                        return "PlcINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 32) {
+                        return "PlcDINT";
+                    }
+                    if (integerTypeReference.getSizeInBits() <= 64) {
+                        return "PlcLINT";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case FLOAT:
+                case UFLOAT: {
+                    FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                    int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
+                        floatTypeReference.getExponent() + floatTypeReference.getMantissa();
+                    if (sizeInBits <= 32) {
+                        return "PlcREAL";
+                    }
+                    if (sizeInBits <= 64) {
+                        return "PlcLREAL";
+                    }
+                    throw new RuntimeException("Unsupported simple type");
+                }
+                case STRING: {
+                    return "PlcSTRING";
+                }
+                case TIME: {
+                    return "PlcTIME";
+                }
+                case DATE: {
+                    return "PlcDATE";
+                }
+                case DATETIME: {
+                    return "PlcDATE_AND_TIME";
+                }
+            }
+            throw new RuntimeException("Unsupported simple type");
+        } else {
+            return (typeReference != null) ? ((ComplexTypeReference) typeReference).getName() : "";
+        }
+    }
+
+    @Override
+    public String getNullValueForTypeReference(TypeReference typeReference) {
+        if(typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case BIT: {
+                    return "false";
+                }
+                case UINT:
+                case INT: {
+                    return "0";
+                }
+                case FLOAT: {
+                    return "0.0";
+                }
+                case STRING: {
+                    return "\"\"";
+                }
+            }
+        } else if(typeReference instanceof ComplexTypeReference) {
+            return "0";
+        }
+        return "null";
+    }
+
+    public int getNumBits(SimpleTypeReference simpleTypeReference) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT: {
+                return 1;
+            }
+            case UINT:
+            case INT: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                return integerTypeReference.getSizeInBits();
+            }
+            case FLOAT: {
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                return floatTypeReference.getSizeInBits();
+            }
+            case STRING: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                return integerTypeReference.getSizeInBits();
+            }
+            default: {
+                return 0;
+            }
+        }
+    }
+
+    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT: {
+                return "io.ReadBit()";
+            }
+            case UINT: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "io.ReadByte(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "io.ReadUshort(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "io.ReadUint(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "io.ReadUlong(" + integerTypeReference.getSizeInBits() + ")";
+                }
+            }
+            case INT: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "io.ReadSbyte(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "io.ReadShort(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "io.ReadInt(" + integerTypeReference.getSizeInBits() + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "io.ReadLong(" + integerTypeReference.getSizeInBits() + ")";
+                }
+            }
+            case FLOAT: {
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                if (floatTypeReference.getSizeInBits() <= 32) {
+                    return "io.ReadFloat(true, " + floatTypeReference.getExponent() + ", " + floatTypeReference.getMantissa() + ")";
+                }
+                if (floatTypeReference.getSizeInBits() <= 64) {
+                    return "io.ReadDouble(true, " + floatTypeReference.getExponent() + ", " + floatTypeReference.getMantissa() + ")";
+                }
+            }
+            case STRING: {
+                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+                return "io.ReadString(" + stringTypeReference.getSizeInBits() + ")";
+            }
+        }
+        return "Hurz";
+    }
+
+    @Override
+    public String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT: {
+                return "io.WriteBit(" + fieldName + ")";
+            }
+            case UINT: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "io.WriteByte(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "io.WriteUshort(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "io.WriteUint(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "io.WriteUlong(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+            }
+            case INT: {
+                IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+                if (integerTypeReference.getSizeInBits() <= 8) {
+                    return "io.WriteSbyte(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 16) {
+                    return "io.WriteShort(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 32) {
+                    return "io.WriteInt(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (integerTypeReference.getSizeInBits() <= 64) {
+                    return "io.WriteLong(" + integerTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+            }
+            case FLOAT:
+            case UFLOAT: {
+                FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+                if (floatTypeReference.getSizeInBits() <= 32) {
+                    return "io.WriteFloat(" + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+                if (floatTypeReference.getSizeInBits() <= 64) {
+                    return "io.WriteDouble(" + floatTypeReference.getSizeInBits() + ", " + fieldName + ")";
+                }
+            }
+            case STRING: {
+                StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+                String encoding = ((stringTypeReference.getEncoding() != null) && (stringTypeReference.getEncoding().length() > 2)) ?
+                    stringTypeReference.getEncoding().substring(1, stringTypeReference.getEncoding().length() - 1) : "UTF-8";
+                return "io.WriteString(" + stringTypeReference.getSizeInBits() + ", \"" +
+                    encoding + "\", " + fieldName + ")";
+            }
+        }
+        return "Hurz";
+    }
+
+    public String getReservedValue(ReservedField reservedField) {
+        final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType());
+        return reservedField.getReferenceValue().toString();
+    }
+
+    public String toParseExpression(TypedField field, Term term, Argument[] parserArguments) {
+        return toTypedParseExpression((field != null) ? field.getType() : null, term, parserArguments);
+    }
+
+    public String toSerializationExpression(TypedField field, Term term, Argument[] serializerArguments) {
+        return toTypedSerializationExpression((field != null) ? field.getType() : null, term, serializerArguments);
+    }
+
+    public String toBooleanParseExpression(Term term, Argument[] parserArguments) {
+        return toTypedParseExpression(new DefaultBooleanTypeReference(), term, parserArguments);
+    }
+
+    public String toBooleanSerializationExpression(Term term, Argument[] serializerArguments) {
+        return toTypedSerializationExpression(new DefaultBooleanTypeReference(), term, serializerArguments);
+    }
+
+    public String toIntegerParseExpression(int sizeInBits, Term term, Argument[] parserArguments) {
+        return toTypedParseExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, parserArguments);
+    }
+
+    public String toIntegerSerializationExpression(int sizeInBits, Term term, Argument[] serializerArguments) {
+        return toTypedSerializationExpression(new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.UINT, sizeInBits), term, serializerArguments);
+    }
+
+    public String toTypedParseExpression(TypeReference fieldType, Term term, Argument[] parserArguments) {
+        return toExpression(fieldType, term, parserArguments, null, false, false);
+    }
+
+    public String toTypedSerializationExpression(TypeReference fieldType, Term term, Argument[] serializerArguments) {
+        return toExpression(fieldType, term, null, serializerArguments, true, false);
+    }
+
+    String getCastExpressionForTypeReference(TypeReference typeReference) {
+        if(typeReference instanceof SimpleTypeReference) {
+            return getLanguageTypeNameForTypeReference(typeReference);
+        } else if(typeReference != null) {
+            return "Cast" + getLanguageTypeNameForTypeReference(typeReference);
+        } else {
+            return "";
+        }
+    }
+
+    private String toExpression(TypeReference fieldType, Term term, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
+        if(term == null) {
+            return "";
+        }
+        if(term instanceof Literal) {
+            if(term instanceof NullLiteral) {
+                return "nil";
+            } else if(term instanceof BooleanLiteral) {
+                return getCastExpressionForTypeReference(fieldType) + "(" + ((BooleanLiteral) term).getValue() + ")";
+            } else if(term instanceof NumericLiteral) {
+                return getCastExpressionForTypeReference(fieldType) + "(" + ((NumericLiteral) term).getNumber().toString() + ")";
+            } else if(term instanceof StringLiteral) {
+                return "\"" + ((StringLiteral) term).getValue() + "\"";
+            } else if(term instanceof VariableLiteral) {
+                return toVariableExpression(fieldType, (VariableLiteral) term, parserArguments, serializerArguments, serialize, suppressPointerAccess);
+            } else {
+                throw new RuntimeException("Unsupported Literal type " + term.getClass().getName());
+            }
+        } else if (term instanceof UnaryTerm) {
+            UnaryTerm ut = (UnaryTerm) term;
+            Term a = ut.getA();
+            switch(ut.getOperation()) {
+                case "!":
+                    return "!(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ")";
+                case "-":
+                    return "-(" + getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + "))";
+                case "()":
+                    return getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ")";
+                default:
+                    throw new RuntimeException("Unsupported unary operation type " + ut.getOperation());
+            }
+        } else if (term instanceof BinaryTerm) {
+            BinaryTerm bt = (BinaryTerm) term;
+            Term a = bt.getA();
+            Term b = bt.getB();
+            String operation = bt.getOperation();
+            switch (operation) {
+                case "^":
+                    return "Math.pow(" +
+                        getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + "), " +
+                        getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + "))";
+                // If we start casting for comparisons, equals or non equals, really messy things happen.
+                case "==":
+                case "!=":
+                case ">":
+                case "<":
+                case ">=":
+                case "<=":
+                    // For every access of optional elements we need pointer access ...
+                    // Except for doing a nil or not-nil check :-(
+                    // So in case of such a check, we need to suppress the pointer-access.
+                    boolean suppressPointerAccessOverride = (operation.equals("==") || operation.equals("!=")) && ((a instanceof NullLiteral) || (b instanceof NullLiteral));
+                    return "bool((" + toExpression(null, a, parserArguments, serializerArguments, serialize, suppressPointerAccessOverride) + ") " +
+                        operation +
+                        " (" + toExpression(null, b, parserArguments, serializerArguments, serialize, suppressPointerAccessOverride) + "))";
+                default:
+                    return getCastExpressionForTypeReference(fieldType) + "(" + toExpression(fieldType, a, parserArguments, serializerArguments, serialize, false) + ") " +
+                        operation + " " +
+                        getCastExpressionForTypeReference(fieldType) +"(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + ")";
+            }
+        } else if (term instanceof TernaryTerm) {
+            TernaryTerm tt = (TernaryTerm) term;
+            if ("if".equals(tt.getOperation())) {
+                Term a = tt.getA();
+                Term b = tt.getB();
+                Term c = tt.getC();
+                // TODO: This is not quite correct with the cast to uint16
+                return "utils.InlineIf(" + toExpression(new DefaultBooleanTypeReference(), a, parserArguments, serializerArguments, serialize, false) + ", " +
+                    "uint16(" + toExpression(fieldType, b, parserArguments, serializerArguments, serialize, false) + "), " +
+                    "uint16(" + toExpression(fieldType, c, parserArguments, serializerArguments, serialize, false) + "))";
+            } else {
+                throw new RuntimeException("Unsupported ternary operation type " + tt.getOperation());
+            }
+        } else {
+            throw new RuntimeException("Unsupported Term type " + term.getClass().getName());
+        }
+    }
+
+    private String toVariableExpression(TypeReference typeReference, VariableLiteral vl, Argument[] parserArguments, Argument[] serializerArguments, boolean serialize, boolean suppressPointerAccess) {
+        if ("lengthInBytes".equals(vl.getName())) {
+            return (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBytes()" + (serialize ? ")" : "");
+        } else if ("lengthInBits".equals(vl.getName())) {
+            return (serialize ? getCastExpressionForTypeReference(typeReference) + "(m." : "") + "LengthInBits()" + (serialize ? ")" : "");
+        }
+        // If this literal references an Enum type, then we have to output it differently.
+        else if (getTypeDefinitions().get(vl.getName()) instanceof EnumTypeDefinition) {
+            return vl.getName() + "_" + vl.getChild().getName() +
+                ((vl.getChild().getChild() != null) ?
+                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+        }
+        // If we are accessing enum constants, these also need to be output differently.
+        else if ((getFieldForNameFromCurrent(vl.getName()) instanceof EnumField) && (vl.getChild() != null)) {
+            return vl.getName() + "." + StringUtils.capitalize(vl.getChild().getName()) + "()" +
+                ((vl.getChild().getChild() != null) ?
+                    "." + toVariableExpression(typeReference, vl.getChild().getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+        }
+        // If we are accessing optional fields of simple type, we need to use pointer-access.
+        else if (!serialize && (getFieldForNameFromCurrent(vl.getName()) instanceof OptionalField) &&
+            (((OptionalField) getFieldForNameFromCurrent(vl.getName())).getType() instanceof SimpleTypeReference)) {
+            return "(*" + vl.getName() + ")" +
+                ((vl.getChild() != null) ?
+                    "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, serialize, suppressPointerAccess) : "");
+        }
+        // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
+        else if ("CAST".equals(vl.getName())) {
+            if ((vl.getArgs() == null) || (vl.getArgs().size() != 2)) {
+                throw new RuntimeException("A CAST expression expects exactly two arguments.");
+            }
+            VariableLiteral typeLiteral = (VariableLiteral) vl.getArgs().get(1);
+            final TypeDefinition typeDefinition = getTypeDefinitions().get(typeLiteral.getName());
+            TypeReference type = typeDefinition.getTypeReference();
+            StringBuilder sb = new StringBuilder();
+            if (type instanceof ComplexTypeReference) {
+                sb.append("Cast");
+            }
+            sb.append(typeLiteral.getName());
+            sb.append("(").append(toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess)).append(")");
+            return sb.toString() + ((vl.getChild() != null) ? "." + StringUtils.capitalize(toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess)) : "");
+        } else if ("STATIC_CALL".equals(vl.getName())) {
+            StringBuilder sb = new StringBuilder();
+            if (!(vl.getArgs().get(0) instanceof StringLiteral)) {
+                throw new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral");
+            }
+            // Get the class and method name
+            String staticCall = ((StringLiteral) vl.getArgs().get(0)).getValue();
+            // Cut off the double-quotes
+            staticCall = staticCall.substring(1, staticCall.length() - 1);
+            // 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("(");
+            for (int i = 1; i < vl.getArgs().size(); i++) {
+                Term arg = vl.getArgs().get(i);
+                if (i > 1) {
+                    sb.append(", ");
+                }
+                if (arg instanceof VariableLiteral) {
+                    VariableLiteral va = (VariableLiteral) arg;
+                    // "io" is the default name of the reader argument which is always available.
+                    boolean isParserArg = "io".equals(va.getName()) || ((getThisTypeDefinition() instanceof DataIoTypeDefinition) && "_value".equals(va.getName()));
+                    boolean isTypeArg = "_type".equals(va.getName());
+                    if (!isParserArg && !isTypeArg && parserArguments != null) {
+                        for (Argument parserArgument : parserArguments) {
+                            if (parserArgument.getName().equals(va.getName())) {
+                                isParserArg = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (isParserArg) {
+                        if(va.getName().equals("_value")) {
+                            sb.append(va.getName().substring(1) + ((va.getChild() != null) ?
+                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : ""));
+                        } else {
+                            sb.append(va.getName() + ((va.getChild() != null) ?
+                                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : ""));
+                        }
+                    }
+                    // We have to manually evaluate the type information at code-generation time.
+                    else if (isTypeArg) {
+                        String part = va.getChild().getName();
+                        switch (part) {
+                            case "name":
+//                                sb.append("\"").append(field.getTypeName()).append("\"");
+                                break;
+                            case "length":
+                                sb.append("\"").append(((SimpleTypeReference) typeReference).getSizeInBits()).append("\"");
+                                break;
+                            case "encoding":
+                                String encoding = ((StringTypeReference) typeReference).getEncoding();
+                                // Cut off the single quotes.
+                                encoding = encoding.substring(1, encoding.length() - 1);
+                                sb.append("\"").append(encoding).append("\"");
+                                break;
+                        }
+                    } else {
+                        sb.append(toVariableExpression(typeReference, va, parserArguments, serializerArguments, serialize, suppressPointerAccess));
+                    }
+                } else if (arg instanceof StringLiteral) {
+                    sb.append(((StringLiteral) arg).getValue());
+                }
+            }
+            sb.append(")");
+            return sb.toString();
+        } else if ("COUNT".equals(vl.getName())) {
+            return (typeReference instanceof SimpleTypeReference ? getCastExpressionForTypeReference(typeReference) : "") + "(len(" +
+                toVariableExpression(typeReference, (VariableLiteral) vl.getArgs().get(0), parserArguments, serializerArguments, serialize, suppressPointerAccess) +
+                "))";
+        } else if ("ARRAY_SIZE_IN_BYTES".equals(vl.getName())) {
+            VariableLiteral va = (VariableLiteral) vl.getArgs().get(0);
+            // "io" and "m" are always available in every parser.
+            boolean isSerializerArg = "io".equals(va.getName()) || "m".equals(va.getName()) || "element".equals(va.getName());
+            if (!isSerializerArg && serializerArguments != null) {
+                for (Argument serializerArgument : serializerArguments) {
+                    if (serializerArgument.getName().equals(va.getName())) {
+                        isSerializerArg = true;
+                        break;
+                    }
+                }
+            }
+            StringBuilder sb = new StringBuilder();
+            if (isSerializerArg) {
+                sb.append(va.getName()).append(((va.getChild() != null) ? "." + toVariableExpression(typeReference, va.getChild(), parserArguments, serializerArguments, true, suppressPointerAccess) : ""));
+            } else {
+                sb.append(toVariableExpression(typeReference, va, parserArguments, serializerArguments, true, suppressPointerAccess));
+            }
+            return getCastExpressionForTypeReference(typeReference) + "(" + ((VariableLiteral) vl.getArgs().get(0)).getName() + "ArraySizeInBytes(" + sb.toString() + "))";
+        }
+        else if("CEIL".equals(vl.getName())) {
+            Term va = vl.getArgs().get(0);
+            // The Ceil function expects 64 bit floating point values.
+            TypeReference tr = new DefaultFloatTypeReference(SimpleTypeReference.SimpleBaseType.FLOAT, 11, 52);
+            return "math.Ceil(" + toExpression(tr, va, parserArguments, serializerArguments, serialize, suppressPointerAccess) + ")";
+        }
+        // All uppercase names are not fields, but utility methods.
+        else if (vl.getName().equals(vl.getName().toUpperCase())) {
+            StringBuilder sb = new StringBuilder(vl.getName());
+            if (vl.getArgs() != null) {
+                sb.append("(");
+                boolean firstArg = true;
+                for (Term arg : vl.getArgs()) {
+                    if (!firstArg) {
+                        sb.append(", ");
+                    }
+                    sb.append(toExpression(typeReference, arg, parserArguments, serializerArguments, serialize, suppressPointerAccess));
+                    firstArg = false;
+                }
+                sb.append(")");
+            }
+            if (vl.getIndex() != VariableLiteral.NO_INDEX) {
+                sb.append("[").append(vl.getIndex()).append("]");
+            }
+            return sb.toString() + ((vl.getChild() != null) ?
+                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+        }
+        // If the current property references a discriminator value, we have to serialize it differently.
+        else if ((getFieldForNameFromCurrentOrParent(vl.getName()) != null) && (getFieldForNameFromCurrentOrParent(vl.getName()) instanceof DiscriminatorField)) {
+            final DiscriminatorField discriminatorField = (DiscriminatorField) getFieldForNameFromCurrentOrParent(vl.getName());
+            System.out.println(discriminatorField);
+        }
+        // If the current property references a parserArguments property and that is a discriminator property, we also have to serialize it differently..
+        else if ((vl.getChild() != null) && (getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName()) != null)) {
+            final Optional<TypeReference> typeReferenceForProperty = getTypeReferenceForProperty(((ComplexTypeDefinition) getThisTypeDefinition()), vl.getName());
+            if(typeReferenceForProperty.isPresent() && typeReferenceForProperty.get() instanceof ComplexTypeReference) {
+                final TypeReference complexTypeReference = typeReferenceForProperty.get();
+                TypeDefinition typeDefinition = getTypeDefinitionForTypeReference(complexTypeReference);
+                if(typeDefinition instanceof ComplexTypeDefinition) {
+                    ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) typeDefinition;
+                    String childProperty = vl.getChild().getName();
+                    final Optional<Field> matchingDiscriminatorField = complexTypeDefinition.getFields().stream().filter(field -> (field instanceof DiscriminatorField) && ((DiscriminatorField) field).getName().equals(childProperty)).findFirst();
+                    if(matchingDiscriminatorField.isPresent()) {
+                        return "Cast" + getLanguageTypeNameForTypeReference(complexTypeReference) + "(" + vl.getName() + ")." + StringUtils.capitalize(childProperty) + "()";
+                    }
+                }
+            }
+        }
+        // If the current term references a serialization argument, handle it differently (don't prefix it with "m.")
+        else if((serializerArguments != null) && Arrays.stream(serializerArguments).anyMatch(argument -> argument.getName().equals(vl.getName()))) {
+            return vl.getName() + ((vl.getChild() != null) ?
+                "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+        }
+        return (serialize ? "m." + StringUtils.capitalize(vl.getName()) : vl.getName()) + ((vl.getChild() != null) ?
+            "." + toVariableExpression(typeReference, vl.getChild(), parserArguments, serializerArguments, false, suppressPointerAccess) : "");
+    }
+
+    public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, Argument[] parserArguments) {
+        int sizeInBits = 0;
+        StringBuilder sb = new StringBuilder("");
+        for (Field field : complexTypeDefinition.getFields()) {
+            if(field instanceof ArrayField) {
+                ArrayField arrayField = (ArrayField) field;
+                final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
+                switch (arrayField.getLoopType()) {
+                    case COUNT:
+                        sb.append("(").append(toTypedSerializationExpression(type, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
+                        break;
+                    case LENGTH:
+                        sb.append("(").append(toTypedSerializationExpression(type, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
+                        break;
+                    case TERMINATED:
+                        // No terminated.
+                        break;
+                }
+            } else if(field instanceof TypedField) {
+                TypedField typedField = (TypedField) field;
+                final TypeReference type = typedField.getType();
+                if(field instanceof ManualField) {
+                    ManualField manualField = (ManualField) field;
+                    sb.append("(").append(toSerializationExpression(manualField, manualField.getLengthExpression(), parserArguments)).append(") + ");
+                }
+                else if(type instanceof SimpleTypeReference) {
+                    SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
+                    sizeInBits += simpleTypeReference.getSizeInBits();
+                } else {
+                    // No ComplexTypeReference supported.
+                }
+            }
+        }
+        return sb.toString() + sizeInBits;
+    }
+
+    public String escapeValue(TypeReference typeReference, String valueString) {
+        if(valueString == null) {
+            return null;
+        }
+        if(typeReference instanceof SimpleTypeReference) {
+            SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+            switch (simpleTypeReference.getBaseType()) {
+                case UINT:
+                case INT:
+                    // If it's a one character string and is numeric, output it as char.
+                    if(!NumberUtils.isParsable(valueString) && (valueString.length() == 1)) {
+                        return "'" + valueString + "'";
+                    }
+                    break;
+                case STRING:
+                    return "\"" + valueString + "\"";
+            }
+        }
+        return valueString;
+    }
+
+    public String escapeEnumValue(TypeReference typeReference, String valueString) {
+        // Currently the only case in which here complex type references are used are when referencing enum constants.
+        if (typeReference instanceof ComplexTypeReference) {
+            // C doesn't like NULL values for enums, so we have to return something else (we'll treat -1 as NULL)
+            if ("null".equals(valueString)) {
+                return "0";
+            }
+            String typeName = valueString.substring(0, valueString.indexOf('.'));
+            String constantName = valueString.substring(valueString.indexOf('.') + 1);
+            return typeName + "_" + constantName;
+        } else {
+            return escapeValue(typeReference, valueString);
+        }
+    }
+
+    public Collection<EnumValue> getUniqueEnumValues(EnumValue[] enumValues) {
+        Map<String, EnumValue> filteredEnumValues = new TreeMap<>();
+        for (EnumValue enumValue : enumValues) {
+            if (!filteredEnumValues.containsKey(enumValue.getValue())) {
+                filteredEnumValues.put(enumValue.getValue(), enumValue);
+            }
+        }
+        return filteredEnumValues.values();
+    }
+
+    public List<String> getRequiredImports() {
+        ComplexTypeDefinition complexTypeDefinition = (ComplexTypeDefinition) getThisTypeDefinition();
+        List<String> imports = new ArrayList<>();
+
+        if(complexTypeDefinition.getAllPropertyFields().stream().anyMatch(field -> isArrayField(field) && getLanguageTypeNameForField(field).equals("int8"))) {
+            imports.add("\"encoding/base64\"");
+        }
+
+        imports.add("\"encoding/xml\"");
+
+        // For "Fields with complex type", constant, typeSwitch,  fields: "errors"
+        if(!complexTypeDefinition.getFields().isEmpty()) {
+            imports.add("\"errors\"");
+        }
+
+        imports.add("\"io\"");
+
+        // At least one reserved field or simple field with complex type
+        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
+            (field instanceof ReservedField))) {
+            imports.add("log \"github.com/sirupsen/logrus\"");
+        }
+
+        // For CEIL functions: "math"
+/*        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
+            FieldUtils.contains(field, "CEIL"))) {
+            imports.add("\"math\"");
+        }*/
+
+        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/utils\"");
+
+        // For Constant field: "strconv"
+        if(complexTypeDefinition.getFields().stream().anyMatch(field ->
+            (field instanceof ConstField))/* || complexTypeDefinition.getAllPropertyFields().stream().anyMatch(
+                propertyField -> isSimpleField(propertyField))*/) {
+            imports.add("\"strconv\"");
+        }
+
+        if(isDiscriminatedParentTypeDefinition()) {
+            imports.add("\"reflect\"");
+            imports.add("\"strings\"");
+        }
+
+        return imports;
+    }
+
+    public List<String> getRequiredImportsForDataIo() {
+        DataIoTypeDefinition dataIo = (DataIoTypeDefinition) getThisTypeDefinition();
+
+        List<String> imports = new ArrayList<>();
+
+        imports.add("\"errors\"");
+        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/model/values\"");
+        imports.add("\"github.com/apache/plc4x/plc4go/internal/plc4go/utils\"");
+        imports.add("api \"github.com/apache/plc4x/plc4go/pkg/plc4go/values\"");
+
+        if(dataIo.getSwitchField().getCases().stream().anyMatch(typeCase ->
+            (typeCase.getName().equals("TIME_OF_DAY") && hasFieldsWithNames(typeCase.getFields(), "hour", "minutes", "seconds")) ||
+                (typeCase.getName().equals("DATE") && hasFieldsWithNames(typeCase.getFields(), "year", "month", "day")) ||
+                (typeCase.getName().equals("DATE_AND_TIME") && hasFieldsWithNames(typeCase.getFields(), "year", "month", "day", "hour", "minutes", "seconds")))) {
+            imports.add("\"time\"");
+        }
+        return imports;
+    }
+
+    public String getVariableName(Field field) {
+        if(!(field instanceof NamedField)) {
+            return "_";
+        }
+        NamedField namedField = (NamedField) field;
+
+        String name = null;
+        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+            if(curField == field) {
+                name = namedField.getName();
+            } else if(name != null) {
+                if(curField instanceof ArrayField) {
+                    ArrayField arrayField = (ArrayField) curField;
+                    if(arrayField.getLoopExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof ChecksumField) {
+                    ChecksumField checksumField = (ChecksumField) curField;
+                    if(checksumField.getChecksumExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof ImplicitField) {
+                    ImplicitField implicitField = (ImplicitField) curField;
+                    if(implicitField.getSerializeExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof ManualArrayField) {
+                    ManualArrayField manualArrayField = (ManualArrayField) curField;
+                    if(manualArrayField.getLengthExpression().contains(name)) {
+                        return name;
+                    }
+                    if(manualArrayField.getLoopExpression().contains(name)) {
+                        return name;
+                    }
+                    if(manualArrayField.getParseExpression().contains(name)) {
+                        return name;
+                    }
+                    if(manualArrayField.getSerializeExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof ManualField) {
+                    ManualField manualField = (ManualField) curField;
+                    if(manualField.getLengthExpression().contains(name)) {
+                        return name;
+                    }
+                    if(manualField.getParseExpression().contains(name)) {
+                        return name;
+                    }
+                    if(manualField.getSerializeExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof OptionalField) {
+                    OptionalField optionalField = (OptionalField) curField;
+                    if(optionalField.getConditionExpression().contains(name)) {
+                        return name;
+                    }
+                } else if(curField instanceof SwitchField) {
+                    SwitchField switchField = (SwitchField) curField;
+                    for (Term discriminatorExpression : switchField.getDiscriminatorExpressions()) {
+                        if(discriminatorExpression.contains(name)) {
+                            return name;
+                        }
+                    }
+                    for (DiscriminatedComplexTypeDefinition curCase : switchField.getCases()) {
+                        for (Argument parserArgument : curCase.getParserArguments()) {
+                            if(parserArgument.getName().equals(name)) {
+                                return name;
+                            }
+                        }
+                    }
+                } else if(curField instanceof VirtualField) {
+                    VirtualField virtualField = (VirtualField) curField;
+                    if(virtualField.getValueExpression().contains(name)) {
+                        return name;
+                    }
+                }
+                if(curField.getParams() != null) {
+                    for (Term param : curField.getParams()) {
+                        if(param.contains(name)) {
+                            return name;
+                        }
+                    }
+                }
+            }
+        }
+
+        return "_";
+    }
+
+    public boolean needsVariable(ArrayField field, String variableName, boolean serialization) {
+        if(!serialization) {
+            if (field.getLoopExpression().contains(variableName)) {
+                return true;
+            }
+        }
+        if((field.getParams() != null) && (field.getParams().length > 0)){
+            for (Term param : field.getParams()) {
+                if(param.contains(variableName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Right now only the ARRAY_SIZE_IN_BYTES requires helpers to be generated.
+     * Also right now only the Modbus protocol requires this and here the referenced
+     * properties are all also members of the current complex type,
+     * so we'll simplify things here for now.
+     *
+     * @param functionName name of the
+     * @return
+     */
+    public Map<String, String> requiresHelperFunctions(String functionName) {
+        Map<String, String> result = new HashMap<>();
+        boolean usesFunction = false;
+        // As the ARRAY_SIZE_IN_BYTES only applies to ArrayFields, search for these
+        for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+            if(curField instanceof ArrayField) {
+                ArrayField arrayField = (ArrayField) curField;
+                if(arrayField.getLoopExpression().contains(functionName)) {
+                    usesFunction = true;
+                }
+                result.put(arrayField.getName(), getLanguageTypeNameForField(arrayField));
+            } else if(curField instanceof ImplicitField) {
+                ImplicitField implicitField = (ImplicitField) curField;
+                if(implicitField.getSerializeExpression().contains(functionName)) {
+                    usesFunction = true;
+                }
+            }
+        }
+        if(usesFunction) {
+            return result;
+        } else {
+            return Collections.emptyMap();
+        }
+    }
+
+    public boolean requiresStartPosAndCurPos() {
+        if(getThisTypeDefinition() instanceof ComplexTypeDefinition) {
+            for (Field curField : ((ComplexTypeDefinition) getThisTypeDefinition()).getFields()) {
+                if (requiresVariable(curField, "curPos")) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean requiresVariable(Field curField, String variable) {
+        if(curField instanceof ArrayField) {
+            ArrayField arrayField = (ArrayField) curField;
+            if(arrayField.getLoopExpression().contains(variable)) {
+                return true;
+            }
+        } else if(curField instanceof OptionalField) {
+            OptionalField optionalField = (OptionalField) curField;
+            if(optionalField.getConditionExpression().contains(variable)) {
+                return true;
+            }
+        }
+        if(curField.getParams() != null) {
+            for (Term paramTerm : curField.getParams()) {
+                if (paramTerm.contains(variable)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public Term findTerm(Term baseTerm, String name) {
+        if(baseTerm instanceof VariableLiteral) {
+            VariableLiteral variableLiteral = (VariableLiteral) baseTerm;
+            if(variableLiteral.getName().equals(name)) {
+                return variableLiteral;
+            }
+            if(variableLiteral.getChild() != null) {
+                Term found = findTerm(variableLiteral.getChild(), name);
+                if(found != null) {
+                    return found;
+                }
+            }
+            for (Term arg : variableLiteral.getArgs()) {
+                Term found = findTerm(arg, name);
+                if(found != null) {
+                    return found;
+                }
+            }
+        } else if(baseTerm instanceof UnaryTerm) {
+            UnaryTerm unaryTerm = (UnaryTerm) baseTerm;
+            Term found = findTerm(unaryTerm.getA(), name);
+            if(found != null) {
+                return found;
+            }
+        } else if(baseTerm instanceof BinaryTerm) {
+            BinaryTerm binaryTerm = (BinaryTerm) baseTerm;
+            Term found = findTerm(binaryTerm.getA(), name);
+            if(found != null) {
+                return found;
+            }
+            found = findTerm(binaryTerm.getB(), name);
+            if(found != null) {
+                return found;
+            }
+        } else if(baseTerm instanceof TernaryTerm) {
+            TernaryTerm ternaryTerm = (TernaryTerm) baseTerm;
+            Term found = findTerm(ternaryTerm.getA(), name);
+            if(found != null) {
+                return found;
+            }
+            found = findTerm(ternaryTerm.getB(), name);
+            if(found != null) {
+                return found;
+            }
+            found = findTerm(ternaryTerm.getC(), name);
+            if(found != null) {
+                return found;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/build-utils/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput b/build-utils/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
new file mode 100644
index 0000000..eeaeac5
--- /dev/null
+++ b/build-utils/language-cs/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.plc4x.language.cs.CsLanguageOutput
diff --git a/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh b/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh
new file mode 100644
index 0000000..12aa63c
--- /dev/null
+++ b/build-utils/language-cs/src/main/resources/templates/cs/data-io-template.ftlh
@@ -0,0 +1,206 @@
+<#--
+  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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.cs.CsLanguageTemplateHelper" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/${type.name}.cs
+//
+// 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.
+//
+
+using System;
+using System.Collections.Generic;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+namespace org.apache.plc4net.drivers.${protocolName?replace("-", "")}.${outputFlavor?replace("-", "")}.model
+{
+
+    public class ${type.name}
+    {
+
+        public IPlcValue Parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
+        {
+    <#list type.switchField.cases as case>
+            if (<#if case.discriminatorValues?has_content><#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#else>${discriminatorValue}</#if><#sep> && </#sep></#list></#if>) { // ${case.name}
+        <#assign valueDefined=false>
+        <#if case.name == "Struct">
+                var internalMap = new Dictionary<string, IPlcValue>();
+            <#assign valueDefined=true>
+        </#if>
+        <#list case.fields as field>
+            <#switch field.typeName>
+                <#case "array">
+                    <#assign arrayField = field>
+
+                // Array Field (${field.name});
+                var ${arrayField.name} = new List<IPlcValue>();
+                for (int i = 0; i < ${helper.toParseExpression(null, field.loopExpression, type.parserArguments)}; i++) {
+                    var internalItem = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>Complex type array in data-io parsing currently not implemented</#if>;
+                    ${field.name}.Add(new ${helper.getPlcValueTypeForTypeReference(field.type)}(internalItem));
+                }
+                    <#if field.name == "value">
+                        <#assign valueDefined=true>
+                    </#if>
+                    <#break>
+                <#case "manual">
+                    <#assign manualArrayField = field>
+
+                // Manual Field (${field.name})
+                var ${field.name} = ${helper.toParseExpression(field, field.parseExpression, type.parserArguments)};
+                    <#if field.name == "value">
+                        <#assign valueDefined=true>
+                    </#if>
+                    <#break>
+                <#case "reserved">
+                    <#assign reservedField = field>
+
+                // Reserved Field (Just skip the bytes)
+                ${helper.getReadBufferReadMethodCall(field.type)};
+                    <#break>
+                <#case "simple">
+                    <#assign simpleField = field>
+
+                // Simple Field (${field.name})
+                var ${field.name} = <#if helper.isSimpleTypeReference(field.type)>${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}Parse(io<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>;
+                    <#if case.name == "Struct">
+                internalMap["${case.name}"] = new ${helper.getPlcValueTypeForTypeReference(field.type)}(${field.name});
+                    </#if>
+                    <#assign valueDefined=true>
+                    <#break>
+            </#switch>
+        </#list>
+        <#if valueDefined>
+
+            <#switch case.name>
+                <#case "TIME_OF_DAY">
+                    <#if helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds")>
+                var value = new DateTime(0,0,0, hour, minutes, seconds);
+                    </#if>
+                return new PlcTIME_OF_DAY(value);
+                    <#break>
+                <#case "DATE">
+                    <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day")>
+                var value = new DateTime(year, month, day, 0, 0, 0);
+                    </#if>
+                return new PlcDATE(value);
+                    <#break>
+                <#case "DATE_AND_TIME">
+                    <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds")>
+                var value = new DateTime(year, month, day, hour, minutes, seconds);
+                    </#if>
+                return new PlcDATE_AND_TIME(value);
+                    <#break>
+                <#case "Struct">
+                return new PlcStruct(internalMap);
+                    <#break>
+                <#case "List">
+                return new PlcList(value);
+                    <#break>
+                <#default>
+                return new Plc${case.name}(value);
+            </#switch>
+        </#if>
+            } <#sep>else
+    </#list>
+
+            return null;
+        }
+
+        public void Serialize(WriteBuffer io, IPlcValue value<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>)
+        {
+    <#list type.switchField.cases as case>
+            if (<#if case.discriminatorValues?has_content><#list case.discriminatorValues as discriminatorValue>${helper.toParseExpression(null, type.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)} == <#if helper.discriminatorValueNeedsStringEqualityCheck(type.switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#else>${discriminatorValue}</#if><#sep> && </#sep></#list></#if>) { // ${case.name}
+        <#list case.fields as field>
+            <#switch field.typeName>
+                <#case "array">
+                    <#assign arrayField = field>
+
+                // Array Field (${field.name})
+                for (int i = 0; i < ${helper.toSerializationExpression(null, field.loopExpression, type.parserArguments)}; i++) {
+                    <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getWriteBufferWriteMethodCall(arrayField.type, arrayField.name + ".GetIndex(i).Get" + helper.getLanguageTypeNameForTypeReference(arrayField.type)?cap_first + "()")}<#else>Complex type array in data-io serialization currently not implemented</#if>;
+                }
+                    <#break>
+                <#case "manual">
+                    <#assign manualField = field>
+
+                // Manual Field (${field.name})
+                ${helper.toSerializationExpression(field, manualField.serializeExpression, type.parserArguments)};
+                    <#break>
+                <#case "reserved">
+                    <#assign reservedField = field>
+
+                // Reserved Field (Just skip the bytes)
+                ${helper.getWriteBufferWriteMethodCall(field.type, helper.getReservedValue(field))};
+                    <#break>
+                <#case "simple">
+                    <#assign simpleField = field>
+
+                // Simple Field (${field.name})
+                <#if helper.isSimpleTypeReference(field.type)>${helper.getWriteBufferWriteMethodCall(field.type, "value.Get" + helper.getLanguageTypeNameForTypeReference(field.type)?cap_first + "()")}<#else>${field.type.name}Serialize(io, <#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(field.type, parserArgument?index), true)}) (${helper.toParseExpression(field, parserArgument, type.parserArguments [...]
+                    <#break>
+            </#switch>
+        </#list>
+            } <#sep>else
+    </#list>
+        }
+
+    }
+
+}
+
+</#outputformat>
diff --git a/sandbox/plc4net/.gitignore b/sandbox/plc4net/.gitignore
index 912bc0a..48b4ead 100644
--- a/sandbox/plc4net/.gitignore
+++ b/sandbox/plc4net/.gitignore
@@ -341,4 +341,9 @@ ASALocalRun/
 healthchecksdb
 
 # Backup folder for Package Reference Convert tool in Visual Studio 2017
-MigrationBackup/
\ No newline at end of file
+MigrationBackup/
+
+# Ignore the bin directories
+/api/bin/
+/spi/bin/
+/drivers/knxnetip/bin/
diff --git a/sandbox/plc4net/api/exceptions/PlcConnectionException.cs b/sandbox/plc4net/api/api/exceptions/PlcConnectionException.cs
similarity index 100%
rename from sandbox/plc4net/api/exceptions/PlcConnectionException.cs
rename to sandbox/plc4net/api/api/exceptions/PlcConnectionException.cs
diff --git a/sandbox/plc4net/api/exceptions/PlcException.cs b/sandbox/plc4net/api/api/exceptions/PlcException.cs
similarity index 100%
rename from sandbox/plc4net/api/exceptions/PlcException.cs
rename to sandbox/plc4net/api/api/exceptions/PlcException.cs
diff --git a/sandbox/plc4net/api/exceptions/PlcInvalidFieldException.cs b/sandbox/plc4net/api/api/exceptions/PlcInvalidFieldException.cs
similarity index 100%
rename from sandbox/plc4net/api/exceptions/PlcInvalidFieldException.cs
rename to sandbox/plc4net/api/api/exceptions/PlcInvalidFieldException.cs
diff --git a/sandbox/plc4net/api/messages/IPlcFieldRequest.cs b/sandbox/plc4net/api/api/messages/IPlcFieldRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcFieldRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcFieldRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcFieldResponse.cs b/sandbox/plc4net/api/api/messages/IPlcFieldResponse.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcFieldResponse.cs
rename to sandbox/plc4net/api/api/messages/IPlcFieldResponse.cs
diff --git a/sandbox/plc4net/api/messages/IPlcMessage.cs b/sandbox/plc4net/api/api/messages/IPlcMessage.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcMessage.cs
rename to sandbox/plc4net/api/api/messages/IPlcMessage.cs
diff --git a/sandbox/plc4net/api/messages/IPlcReadRequest.cs b/sandbox/plc4net/api/api/messages/IPlcReadRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcReadRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcReadRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcReadRequestBuilder.cs b/sandbox/plc4net/api/api/messages/IPlcReadRequestBuilder.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcReadRequestBuilder.cs
rename to sandbox/plc4net/api/api/messages/IPlcReadRequestBuilder.cs
diff --git a/sandbox/plc4net/api/messages/IPlcReadResponse.cs b/sandbox/plc4net/api/api/messages/IPlcReadResponse.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcReadResponse.cs
rename to sandbox/plc4net/api/api/messages/IPlcReadResponse.cs
diff --git a/sandbox/plc4net/api/messages/IPlcRequest.cs b/sandbox/plc4net/api/api/messages/IPlcRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcRequestBuilder.cs b/sandbox/plc4net/api/api/messages/IPlcRequestBuilder.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcRequestBuilder.cs
rename to sandbox/plc4net/api/api/messages/IPlcRequestBuilder.cs
diff --git a/sandbox/plc4net/api/messages/IPlcResponse.cs b/sandbox/plc4net/api/api/messages/IPlcResponse.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcResponse.cs
rename to sandbox/plc4net/api/api/messages/IPlcResponse.cs
diff --git a/sandbox/plc4net/api/messages/IPlcSubscriptionEventArgs.cs b/sandbox/plc4net/api/api/messages/IPlcSubscriptionEventArgs.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcSubscriptionEventArgs.cs
rename to sandbox/plc4net/api/api/messages/IPlcSubscriptionEventArgs.cs
diff --git a/sandbox/plc4net/api/messages/IPlcSubscriptionRequest.cs b/sandbox/plc4net/api/api/messages/IPlcSubscriptionRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcSubscriptionRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcSubscriptionRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcSubscriptionRequestBuilder.cs b/sandbox/plc4net/api/api/messages/IPlcSubscriptionRequestBuilder.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcSubscriptionRequestBuilder.cs
rename to sandbox/plc4net/api/api/messages/IPlcSubscriptionRequestBuilder.cs
diff --git a/sandbox/plc4net/api/messages/IPlcSubscriptionResponse.cs b/sandbox/plc4net/api/api/messages/IPlcSubscriptionResponse.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcSubscriptionResponse.cs
rename to sandbox/plc4net/api/api/messages/IPlcSubscriptionResponse.cs
diff --git a/sandbox/plc4net/api/messages/IPlcUnsubscriptionRequest.cs b/sandbox/plc4net/api/api/messages/IPlcUnsubscriptionRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcUnsubscriptionRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcUnsubscriptionRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcUnsubscriptionRequestBuilder.cs b/sandbox/plc4net/api/api/messages/IPlcUnsubscriptionRequestBuilder.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcUnsubscriptionRequestBuilder.cs
rename to sandbox/plc4net/api/api/messages/IPlcUnsubscriptionRequestBuilder.cs
diff --git a/sandbox/plc4net/api/messages/IPlcUnsubscriptionResponse.cs b/sandbox/plc4net/api/api/messages/IPlcUnsubscriptionResponse.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcUnsubscriptionResponse.cs
rename to sandbox/plc4net/api/api/messages/IPlcUnsubscriptionResponse.cs
diff --git a/sandbox/plc4net/api/messages/IPlcWriteRequest.cs b/sandbox/plc4net/api/api/messages/IPlcWriteRequest.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcWriteRequest.cs
rename to sandbox/plc4net/api/api/messages/IPlcWriteRequest.cs
diff --git a/sandbox/plc4net/api/messages/IPlcWriteRequestBuilder.cs b/sandbox/plc4net/api/api/messages/IPlcWriteRequestBuilder.cs
similarity index 100%
rename from sandbox/plc4net/api/messages/IPlcWriteRequestBuilder.cs
rename to sandbox/plc4net/api/api/messages/IPlcWriteRequestBuilder.cs
diff --git a/sandbox/plc4net/api/model/IPlcField.cs b/sandbox/plc4net/api/api/model/IPlcField.cs
similarity index 100%
rename from sandbox/plc4net/api/model/IPlcField.cs
rename to sandbox/plc4net/api/api/model/IPlcField.cs
diff --git a/sandbox/plc4net/api/model/IPlcSubscriptionHandle.cs b/sandbox/plc4net/api/api/model/IPlcSubscriptionHandle.cs
similarity index 100%
rename from sandbox/plc4net/api/model/IPlcSubscriptionHandle.cs
rename to sandbox/plc4net/api/api/model/IPlcSubscriptionHandle.cs
diff --git a/sandbox/plc4net/api/types/PlcResponseCode.cs b/sandbox/plc4net/api/api/types/PlcResponseCode.cs
similarity index 100%
rename from sandbox/plc4net/api/types/PlcResponseCode.cs
rename to sandbox/plc4net/api/api/types/PlcResponseCode.cs
diff --git a/sandbox/plc4net/api/api/value/IPlcValue.cs b/sandbox/plc4net/api/api/value/IPlcValue.cs
new file mode 100644
index 0000000..e3e29a4
--- /dev/null
+++ b/sandbox/plc4net/api/api/value/IPlcValue.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+
+namespace org.apache.plc4net.api.value
+{
+    public interface IPlcValue
+    {
+        // Simple Types
+        bool IsSimple();
+        bool IsNullable();
+        bool IsNull();
+
+        // Boolean
+        bool IsBool();
+        int GetBoolLength();
+        bool GetBool();
+        bool GetBoolAt(int index);
+        bool[] GetBoolArray();
+
+        // Integer
+        bool IsByte();
+        byte GetByte();
+        bool IsUshort();
+        ushort GetUshort();
+        bool IsUint();
+        uint GetUint();
+        bool IsUlong();
+        ulong GetUlong();
+        bool IsSbyte();
+        sbyte GetSbyte();
+        bool IsShort();
+        short GetShort();
+        bool IsInt();
+        int GetInt();
+        bool IsLong();
+        long GetLong();
+
+        // Floating Point
+        bool IsFloat();
+        float GetFloat();
+        bool IsDouble();
+        double GetDouble();
+
+        // String
+        bool IsString();
+        string GetString();
+
+        // Time
+        bool IsDateTime();
+        DateTime GetDateTime();
+
+        // Raw Access
+        byte[] GetRaw();
+
+        // List Methods
+        bool IsList();
+        int GetLength();
+        IPlcValue GetIndex(int index);
+        IPlcValue[] GetList();
+
+        // Struct Methods
+        bool IsStruct();
+        string[] GetKeys();
+        bool HasKey(string key);
+        IPlcValue GetValue(string key);
+        Dictionary<string, IPlcValue> GetStruct();
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/api/api.csproj b/sandbox/plc4net/api/plc4net-api.csproj
similarity index 66%
copy from sandbox/plc4net/api/api.csproj
copy to sandbox/plc4net/api/plc4net-api.csproj
index eb00812..11ff5a4 100644
--- a/sandbox/plc4net/api/api.csproj
+++ b/sandbox/plc4net/api/plc4net-api.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -19,9 +19,13 @@
 -->
 <Project Sdk="Microsoft.NET.Sdk">
 
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <RootNamespace>org.apache.plc4net</RootNamespace>
-  </PropertyGroup>
+    <PropertyGroup>
+        <TargetFramework>netstandard2.0</TargetFramework>
+        <RootNamespace>org.apache.plc4net</RootNamespace>
+        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+        <Authors>Apache PLC4X</Authors>
+        <Copyright>The Apache Software Foundation</Copyright>
+        <PackageProjectUrl>https://plc4x.apache.org</PackageProjectUrl>
+    </PropertyGroup>
 
 </Project>
diff --git a/sandbox/plc4net/drivers/knxnetip/generated/sources/knxnetip/readwrite/model/KnxDatapoint.cs b/sandbox/plc4net/drivers/knxnetip/generated/sources/knxnetip/readwrite/model/KnxDatapoint.cs
new file mode 100644
index 0000000..9a9d0b3
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/generated/sources/knxnetip/readwrite/model/KnxDatapoint.cs
@@ -0,0 +1,3955 @@
+//
+// 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.
+//
+
+using System;
+using System.Collections.Generic;
+using org.apache.plc4net.api.value;
+using org.apache.plc4net.spi.generation;
+using org.apache.plc4net.spi.model.values;
+
+namespace org.apache.plc4net.drivers.knxnetip.readwrite.model
+{
+
+    public class KnxDatapoint
+    {
+
+        public IPlcValue Parse(ReadBuffer io, string formatName)
+        {
+            if (formatName == "B1") { // BOOL
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(7);
+
+                // Simple Field (value)
+                var value = io.ReadBit();
+
+                return new PlcBOOL(value);
+            } else
+            if (formatName == "B2") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(6);
+
+                // Simple Field (control)
+                var control = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(control);
+
+                // Simple Field (value)
+                var value = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(value);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B1U3") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (control)
+                var control = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(control);
+
+                // Simple Field (value)
+                var value = io.ReadByte(3);
+                internalMap["Struct"] = new PlcUSINT(value);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "A8_ASCII") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadString(8);
+
+                return new PlcSTRING(value);
+            } else
+            if (formatName == "A8_8859_1") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadString(8);
+
+                return new PlcSTRING(value);
+            } else
+            if (formatName == "U8") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadByte(8);
+
+                return new PlcUSINT(value);
+            } else
+            if (formatName == "V8") { // SINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadSbyte(8);
+
+                return new PlcSINT(value);
+            } else
+            if (formatName == "B5N3") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (a)
+                var a = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(a);
+
+                // Simple Field (b)
+                var b = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(b);
+
+                // Simple Field (c)
+                var c = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(c);
+
+                // Simple Field (d)
+                var d = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(d);
+
+                // Simple Field (e)
+                var e = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(e);
+
+                // Simple Field (value)
+                var value = io.ReadSbyte(8);
+                internalMap["Struct"] = new PlcSINT(value);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16") { // UINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadUshort(16);
+
+                return new PlcUINT(value);
+            } else
+            if (formatName == "V16") { // INT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadShort(16);
+
+                return new PlcINT(value);
+            } else
+            if (formatName == "F16") { // REAL
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadFloat(true, 4, 11);
+
+                return new PlcREAL(value);
+            } else
+            if (formatName == "N3N5r2N6r2N6") { // TIME_OF_DAY
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (day)
+                var day = io.ReadByte(3);
+
+                // Simple Field (hour)
+                var hour = io.ReadByte(5);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (minutes)
+                var minutes = io.ReadByte(6);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (seconds)
+                var seconds = io.ReadByte(6);
+
+                var value = new DateTime(0,0,0, hour, minutes, seconds);
+                return new PlcTIME_OF_DAY(value);
+            } else
+            if (formatName == "r3N5r4N4r1U7") { // DATE
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (day)
+                var day = io.ReadByte(5);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (month)
+                var month = io.ReadByte(4);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(1);
+
+                // Simple Field (year)
+                var year = io.ReadByte(7);
+
+                var value = new DateTime(year, month, day, 0, 0, 0);
+                return new PlcDATE(value);
+            } else
+            if (formatName == "U32") { // UDINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadUint(32);
+
+                return new PlcUDINT(value);
+            } else
+            if (formatName == "V32") { // DINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadInt(32);
+
+                return new PlcDINT(value);
+            } else
+            if (formatName == "F32") { // REAL
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadFloat(true, 8, 23);
+
+                return new PlcREAL(value);
+            } else
+            if (formatName == "U4U4U4U4U4U4B4N4") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (d6)
+                var d6 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d6);
+
+                // Simple Field (d5)
+                var d5 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d5);
+
+                // Simple Field (d4)
+                var d4 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d4);
+
+                // Simple Field (d3)
+                var d3 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d3);
+
+                // Simple Field (d2)
+                var d2 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d2);
+
+                // Simple Field (d1)
+                var d1 = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(d1);
+
+                // Simple Field (e)
+                var e = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(e);
+
+                // Simple Field (p)
+                var p = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(p);
+
+                // Simple Field (d)
+                var d = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(d);
+
+                // Simple Field (c)
+                var c = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(c);
+
+                // Simple Field (index)
+                var index = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(index);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "A112_ASCII") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadString(112);
+
+                return new PlcSTRING(value);
+            } else
+            if (formatName == "A112_8859_1") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadString(112);
+
+                return new PlcSTRING(value);
+            } else
+            if (formatName == "r2U6") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (value)
+                var value = io.ReadByte(6);
+
+                return new PlcUSINT(value);
+            } else
+            if (formatName == "B1r1U6") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (learn)
+                var learn = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(learn);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(1);
+
+                // Simple Field (sceneNumber)
+                var sceneNumber = io.ReadByte(6);
+                internalMap["Struct"] = new PlcUSINT(sceneNumber);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8r4U4r3U5U3U5r2U6r2U6B16") { // DATE_AND_TIME
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (year)
+                var year = io.ReadByte(8);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (month)
+                var month = io.ReadByte(4);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (day)
+                var day = io.ReadByte(5);
+
+                // Simple Field (dayOfWeek)
+                var dayOfWeek = io.ReadByte(3);
+
+                // Simple Field (hour)
+                var hour = io.ReadByte(5);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (minutes)
+                var minutes = io.ReadByte(6);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (seconds)
+                var seconds = io.ReadByte(6);
+
+                // Simple Field (fault)
+                var fault = io.ReadBit();
+
+                // Simple Field (workingDay)
+                var workingDay = io.ReadBit();
+
+                // Simple Field (noWorkingDay)
+                var noWorkingDay = io.ReadBit();
+
+                // Simple Field (noYear)
+                var noYear = io.ReadBit();
+
+                // Simple Field (noMonthAndDay)
+                var noMonthAndDay = io.ReadBit();
+
+                // Simple Field (noDayOfWeek)
+                var noDayOfWeek = io.ReadBit();
+
+                // Simple Field (noTime)
+                var noTime = io.ReadBit();
+
+                // Simple Field (standardSummerTime)
+                var standardSummerTime = io.ReadBit();
+
+                // Simple Field (clockWithSyncSignal)
+                var clockWithSyncSignal = io.ReadBit();
+
+                var value = new DateTime(year, month, day, hour, minutes, seconds);
+                return new PlcDATE_AND_TIME(value);
+            } else
+            if (formatName == "N8") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadByte(8);
+
+                return new PlcUSINT(value);
+            } else
+            if (formatName == "B8") { // BYTE
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadByte(8);
+
+                return new PlcBYTE(value);
+            } else
+            if (formatName == "B16") { // WORD
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadUshort(16);
+
+                return new PlcWORD(value);
+            } else
+            if (formatName == "U4U4") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (busy)
+                var busy = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(busy);
+
+                // Simple Field (nak)
+                var nak = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(nak);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "r1b1U6") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(1);
+
+                // Simple Field (sceneActive)
+                var sceneActive = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(sceneActive);
+
+                // Simple Field (sceneNumber)
+                var sceneNumber = io.ReadByte(6);
+                internalMap["Struct"] = new PlcUSINT(sceneNumber);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B32") { // DWORD
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadUint(32);
+
+                return new PlcDWORD(value);
+            } else
+            if (formatName == "V64") { // LINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (value)
+                var value = io.ReadLong(64);
+
+                return new PlcLINT(value);
+            } else
+            if (formatName == "B24") { // List
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Array Field (value);
+                var value = new List<IPlcValue>();
+                for (int i = 0; i < (24); i++) {
+                    var internalItem = io.ReadBit();
+                    value.Add(new PlcBOOL(internalItem));
+                }
+
+                return new PlcList(value);
+            } else
+            if (formatName == "N3") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (value)
+                var value = io.ReadByte(3);
+
+                return new PlcUSINT(value);
+            } else
+            if (formatName == "B1Z8HeatingOrCoolingZ") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(7);
+
+                // Simple Field (heating)
+                var heating = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(heating);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B1Z8BinaryValueZ") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(7);
+
+                // Simple Field (high)
+                var high = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(high);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8HvacOperatingMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (hvacOperatingMode)
+                var hvacOperatingMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacOperatingMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8DhwMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (dhwMode)
+                var dhwMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(dhwMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8HvacControllingMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (hvacControllingMode)
+                var hvacControllingMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacControllingMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8EnableHeatingOrCoolingStage") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (enableHeatingOrCoolingStage)
+                var enableHeatingOrCoolingStage = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(enableHeatingOrCoolingStage);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8BuildingMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (buildingMode)
+                var buildingMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(buildingMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8OccupancyMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (occupancyMode)
+                var occupancyMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(occupancyMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N8Z8EmergencyMode") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (hvacEmergencyMode)
+                var hvacEmergencyMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacEmergencyMode);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8Z8Rel") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (relValue)
+                var relValue = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8Z8Counter") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (counterValue)
+                var counterValue = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(counterValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8TimePeriod") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (timePeriod)
+                var timePeriod = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(timePeriod);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8FlowRate") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (flowRate)
+                var flowRate = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(flowRate);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8Counter") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (counterValue)
+                var counterValue = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(counterValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8ElectricCurrent") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (electricalCurrent)
+                var electricalCurrent = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(electricalCurrent);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8Power") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (power)
+                var power = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(power);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8AtmPressure") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (atmPressure)
+                var atmPressure = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(atmPressure);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8PercentValue") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (percentValue)
+                var percentValue = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(percentValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8HvacAirQuality") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (ppmResolution)
+                var ppmResolution = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(ppmResolution);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8WindSpeed") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (windSpeed)
+                var windSpeed = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(windSpeed);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8SunIntensity") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (sunIntensity)
+                var sunIntensity = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(sunIntensity);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16Z8HvacAirFlow") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (airFlow)
+                var airFlow = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(airFlow);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V8Z8RelSignedValue") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (relSignedValue)
+                var relSignedValue = io.ReadSbyte(8);
+                internalMap["Struct"] = new PlcSINT(relSignedValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16Z8DeltaTime") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (deltaTime)
+                var deltaTime = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(deltaTime);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16Z8RelSignedValue") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (relSignedValue)
+                var relSignedValue = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(relSignedValue);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16N8HvacModeAndTimeDelay") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (hvacMode)
+                var hvacMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16N8DhwModeAndTimeDelay") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (dhwMode)
+                var dhwMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(dhwMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16N8OccupancyModeAndTimeDelay") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (occupationMode)
+                var occupationMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(occupationMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16N8BuildingModeAndTimeDelay") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (buildingMode)
+                var buildingMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(buildingMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8StatusBurnerController") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (actualRelativePower)
+                var actualRelativePower = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(actualRelativePower);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (stage2Active)
+                var stage2Active = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage2Active);
+
+                // Simple Field (stage1Active)
+                var stage1Active = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage1Active);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (actualRelativePowerValid)
+                var actualRelativePowerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(actualRelativePowerValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8LockingSignal") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (requestedPowerReduction)
+                var requestedPowerReduction = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(requestedPowerReduction);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(6);
+
+                // Simple Field (critical)
+                var critical = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(critical);
+
+                // Simple Field (requestedPowerReductionValid)
+                var requestedPowerReductionValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(requestedPowerReductionValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8BoilerControllerDemandSignal") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (relativeDemand)
+                var relativeDemand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativeDemand);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(6);
+
+                // Simple Field (controlsOperationStage2)
+                var controlsOperationStage2 = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(controlsOperationStage2);
+
+                // Simple Field (controlsOperationStage1)
+                var controlsOperationStage1 = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(controlsOperationStage1);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8ActuatorPositionDemand") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (actuatorPositionDemand)
+                var actuatorPositionDemand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(actuatorPositionDemand);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (emergencyDemand)
+                var emergencyDemand = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(emergencyDemand);
+
+                // Simple Field (shiftLoadPriority)
+                var shiftLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(shiftLoadPriority);
+
+                // Simple Field (absoluteLoadPriority)
+                var absoluteLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(absoluteLoadPriority);
+
+                // Simple Field (actuatorPositionDemandValid)
+                var actuatorPositionDemandValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(actuatorPositionDemandValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8ActuatorPositionStatus") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (actualActuatorPosition)
+                var actualActuatorPosition = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(actualActuatorPosition);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (synchronizationMode)
+                var synchronizationMode = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(synchronizationMode);
+
+                // Simple Field (valveKick)
+                var valveKick = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(valveKick);
+
+                // Simple Field (callibrationMode)
+                var callibrationMode = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(callibrationMode);
+
+                // Simple Field (positionManuallyOverridden)
+                var positionManuallyOverridden = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(positionManuallyOverridden);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8B8StatusLightingActuator") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (lightingLevel)
+                var lightingLevel = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(lightingLevel);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (localOverride)
+                var localOverride = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(localOverride);
+
+                // Simple Field (dimming)
+                var dimming = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(dimming);
+
+                // Simple Field (staircaseLightingFunction)
+                var staircaseLightingFunction = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(staircaseLightingFunction);
+
+                // Simple Field (nightMode)
+                var nightMode = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(nightMode);
+
+                // Simple Field (forced)
+                var forced = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(forced);
+
+                // Simple Field (locked)
+                var locked = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(locked);
+
+                // Simple Field (lightingLevelValid)
+                var lightingLevelValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(lightingLevelValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16B8HeatProducerManagerStatus") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (tempFlowProdSegmH)
+                var tempFlowProdSegmH = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(tempFlowProdSegmH);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (temporarilyOff)
+                var temporarilyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(temporarilyOff);
+
+                // Simple Field (permanentlyOff)
+                var permanentlyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(permanentlyOff);
+
+                // Simple Field (switchedOffSummerMode)
+                var switchedOffSummerMode = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(switchedOffSummerMode);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (tempFlowProdSegmHValid)
+                var tempFlowProdSegmHValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(tempFlowProdSegmHValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16B8RoomTemperatureDemand") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (roomTemperatureDemand)
+                var roomTemperatureDemand = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(roomTemperatureDemand);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (emergencyDemand)
+                var emergencyDemand = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(emergencyDemand);
+
+                // Simple Field (shiftLoadPriority)
+                var shiftLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(shiftLoadPriority);
+
+                // Simple Field (absoluteLoadPriority)
+                var absoluteLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(absoluteLoadPriority);
+
+                // Simple Field (roomTemperatureDemandValid)
+                var roomTemperatureDemandValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(roomTemperatureDemandValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16B8ColdWaterProducerManagerStatus") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (flowTemperatureProdSegmC)
+                var flowTemperatureProdSegmC = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(flowTemperatureProdSegmC);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (temporarilyOff)
+                var temporarilyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(temporarilyOff);
+
+                // Simple Field (permanentlyOff)
+                var permanentlyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(permanentlyOff);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (flowTemperatureProdSegmCValid)
+                var flowTemperatureProdSegmCValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(flowTemperatureProdSegmCValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16B8WaterTemperatureControllerStatus") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (actualTemperature)
+                var actualTemperature = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(actualTemperature);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (controllerWorking)
+                var controllerWorking = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(controllerWorking);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (actualTemperatureValid)
+                var actualTemperatureValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(actualTemperatureValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16B16") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (flowTemperatureDemand)
+                var flowTemperatureDemand = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(flowTemperatureDemand);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (demandFromDhwWhileLegionellaFunctionIsActive)
+                var demandFromDhwWhileLegionellaFunctionIsActive = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(demandFromDhwWhileLegionellaFunctionIsActive);
+
+                // Simple Field (emergencyDemandForFrostProtection)
+                var emergencyDemandForFrostProtection = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(emergencyDemandForFrostProtection);
+
+                // Simple Field (requestForWaterCirculationInPrimaryDistributionSegment)
+                var requestForWaterCirculationInPrimaryDistributionSegment = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(requestForWaterCirculationInPrimaryDistributionSegment);
+
+                // Simple Field (demandFromAuxillaryHeatOrCoolConsumer)
+                var demandFromAuxillaryHeatOrCoolConsumer = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(demandFromAuxillaryHeatOrCoolConsumer);
+
+                // Simple Field (demandFromVentilation)
+                var demandFromVentilation = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(demandFromVentilation);
+
+                // Simple Field (demandForRoomHeatingOrCooling)
+                var demandForRoomHeatingOrCooling = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(demandForRoomHeatingOrCooling);
+
+                // Simple Field (heatDemandFromDhw)
+                var heatDemandFromDhw = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(heatDemandFromDhw);
+
+                // Simple Field (flowTemperatureDemandIsMin)
+                var flowTemperatureDemandIsMin = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(flowTemperatureDemandIsMin);
+
+                // Simple Field (flowTemperatureDemandIsMax)
+                var flowTemperatureDemandIsMax = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(flowTemperatureDemandIsMax);
+
+                // Simple Field (shiftLoadPriority)
+                var shiftLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(shiftLoadPriority);
+
+                // Simple Field (absoluteLoadPriority)
+                var absoluteLoadPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(absoluteLoadPriority);
+
+                // Simple Field (flowTemperatureDemandValid)
+                var flowTemperatureDemandValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(flowTemperatureDemandValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8N8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (energyDemand)
+                var energyDemand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(energyDemand);
+
+                // Simple Field (actualControllerMode)
+                var actualControllerMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(actualControllerMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16V16RoomTemperature") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointComfort)
+                var temperatureSetpointComfort = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointComfort);
+
+                // Simple Field (temperatureSetpointStandby)
+                var temperatureSetpointStandby = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointStandby);
+
+                // Simple Field (temperatureSetpointEco)
+                var temperatureSetpointEco = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointEco);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16V16RoomTemperatureShift") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointShiftComfort)
+                var temperatureSetpointShiftComfort = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftComfort);
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                var temperatureSetpointShiftStandby = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftStandby);
+
+                // Simple Field (temperatureSetpointShiftEco)
+                var temperatureSetpointShiftEco = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftEco);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16V16V16RoomTemperature") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointComfort)
+                var temperatureSetpointComfort = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointComfort);
+
+                // Simple Field (temperatureSetpointStandby)
+                var temperatureSetpointStandby = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointStandby);
+
+                // Simple Field (temperatureSetpointEco)
+                var temperatureSetpointEco = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointEco);
+
+                // Simple Field (temperatureSetpointBProt)
+                var temperatureSetpointBProt = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointBProt);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16V16V16DhwtTemperature") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointLegioProtect)
+                var temperatureSetpointLegioProtect = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointLegioProtect);
+
+                // Simple Field (temperatureSetpointNormal)
+                var temperatureSetpointNormal = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointNormal);
+
+                // Simple Field (temperatureSetpointReduced)
+                var temperatureSetpointReduced = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointReduced);
+
+                // Simple Field (temperatureSetpointFrostProtect)
+                var temperatureSetpointFrostProtect = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointFrostProtect);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16V16V16RoomTemperatureShift") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointShiftComfort)
+                var temperatureSetpointShiftComfort = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftComfort);
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                var temperatureSetpointShiftStandby = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftStandby);
+
+                // Simple Field (temperatureSetpointShiftEco)
+                var temperatureSetpointShiftEco = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftEco);
+
+                // Simple Field (temperatureSetpointShiftBProt)
+                var temperatureSetpointShiftBProt = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftBProt);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16U8B8Heat") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (flowTemperatureDemand)
+                var flowTemperatureDemand = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(flowTemperatureDemand);
+
+                // Simple Field (relativePower)
+                var relativePower = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativePower);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(2);
+
+                // Simple Field (boilerEnabled)
+                var boilerEnabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(boilerEnabled);
+
+                // Simple Field (stage2Forced)
+                var stage2Forced = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage2Forced);
+
+                // Simple Field (stage2Enabled)
+                var stage2Enabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage2Enabled);
+
+                // Simple Field (stage1Forced)
+                var stage1Forced = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage1Forced);
+
+                // Simple Field (stage1Enabled)
+                var stage1Enabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage1Enabled);
+
+                // Simple Field (flowTemperatureDemandValid)
+                var flowTemperatureDemandValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(flowTemperatureDemandValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16U8B8ChilledWater") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (chilledWaterFlowTemperatureDemand)
+                var chilledWaterFlowTemperatureDemand = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(chilledWaterFlowTemperatureDemand);
+
+                // Simple Field (relativePower)
+                var relativePower = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativePower);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (chilledWaterPumpEnabled)
+                var chilledWaterPumpEnabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(chilledWaterPumpEnabled);
+
+                // Simple Field (relativePowerValid)
+                var relativePowerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(relativePowerValid);
+
+                // Simple Field (chilledWaterFlowTemperatureDemandValid)
+                var chilledWaterFlowTemperatureDemandValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(chilledWaterFlowTemperatureDemandValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16U8B16Boiler") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (tempBoiler)
+                var tempBoiler = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(tempBoiler);
+
+                // Simple Field (relativePower)
+                var relativePower = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativePower);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (chimneySweepFunctionActive)
+                var chimneySweepFunctionActive = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(chimneySweepFunctionActive);
+
+                // Simple Field (reducedAvailability)
+                var reducedAvailability = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(reducedAvailability);
+
+                // Simple Field (powerLimitBoilerReached)
+                var powerLimitBoilerReached = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(powerLimitBoilerReached);
+
+                // Simple Field (powerLimitStage1Reached)
+                var powerLimitStage1Reached = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(powerLimitStage1Reached);
+
+                // Simple Field (stage2Enabled)
+                var stage2Enabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage2Enabled);
+
+                // Simple Field (stage1Enabled)
+                var stage1Enabled = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(stage1Enabled);
+
+                // Simple Field (boilerTemporarilyNotProvidingHeat)
+                var boilerTemporarilyNotProvidingHeat = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(boilerTemporarilyNotProvidingHeat);
+
+                // Simple Field (permanentlyOff)
+                var permanentlyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(permanentlyOff);
+
+                // Simple Field (boilerSwitchedOffWinterSummerMode)
+                var boilerSwitchedOffWinterSummerMode = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(boilerSwitchedOffWinterSummerMode);
+
+                // Simple Field (boilerFailure)
+                var boilerFailure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(boilerFailure);
+
+                // Simple Field (relativePowerValid)
+                var relativePowerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(relativePowerValid);
+
+                // Simple Field (tempBoilerValid)
+                var tempBoilerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(tempBoilerValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16U8B16Chiller") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (tempChiller)
+                var tempChiller = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(tempChiller);
+
+                // Simple Field (relativePower)
+                var relativePower = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativePower);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (reducedAvailability)
+                var reducedAvailability = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(reducedAvailability);
+
+                // Simple Field (powerLimitChillerReached)
+                var powerLimitChillerReached = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(powerLimitChillerReached);
+
+                // Simple Field (powerLimitCurrentStageReached)
+                var powerLimitCurrentStageReached = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(powerLimitCurrentStageReached);
+
+                // Simple Field (permanentlyOff)
+                var permanentlyOff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(permanentlyOff);
+
+                // Simple Field (chillerFailure)
+                var chillerFailure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(chillerFailure);
+
+                // Simple Field (chillerRunningStatus)
+                var chillerRunningStatus = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(chillerRunningStatus);
+
+                // Simple Field (relativePowerValid)
+                var relativePowerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(relativePowerValid);
+
+                // Simple Field (tempChillerValid)
+                var tempChillerValid = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(tempChillerValid);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16U8N8B8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (nominalPower)
+                var nominalPower = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(nominalPower);
+
+                // Simple Field (relativePowerLimit)
+                var relativePowerLimit = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(relativePowerLimit);
+
+                // Simple Field (burnerType)
+                var burnerType = io.ReadSbyte(8);
+                internalMap["Struct"] = new PlcSINT(burnerType);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (solidState)
+                var solidState = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(solidState);
+
+                // Simple Field (gas)
+                var gas = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(gas);
+
+                // Simple Field (oil)
+                var oil = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(oil);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U5U5U6") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (magicNumber)
+                var magicNumber = io.ReadByte(5);
+                internalMap["Struct"] = new PlcUSINT(magicNumber);
+
+                // Simple Field (versionNumber)
+                var versionNumber = io.ReadByte(5);
+                internalMap["Struct"] = new PlcUSINT(versionNumber);
+
+                // Simple Field (revisionNumber)
+                var revisionNumber = io.ReadByte(6);
+                internalMap["Struct"] = new PlcUSINT(revisionNumber);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V32Z8VolumeLiter") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (volumeLiter)
+                var volumeLiter = io.ReadInt(32);
+                internalMap["Struct"] = new PlcDINT(volumeLiter);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V32Z8FlowRate") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (flowRate)
+                var flowRate = io.ReadInt(32);
+                internalMap["Struct"] = new PlcDINT(flowRate);
+
+                // Simple Field (statusCommand)
+                var statusCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8N8N8N8B8B8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (logNumber)
+                var logNumber = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(logNumber);
+
+                // Simple Field (alarmPriority)
+                var alarmPriority = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(alarmPriority);
+
+                // Simple Field (applicationArea)
+                var applicationArea = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(applicationArea);
+
+                // Simple Field (errorClass)
+                var errorClass = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(errorClass);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(4);
+
+                // Simple Field (errorCode_Sup)
+                var errorCode_Sup = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(errorCode_Sup);
+
+                // Simple Field (alarmText_Sup)
+                var alarmText_Sup = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(alarmText_Sup);
+
+                // Simple Field (timeStamp_Sup)
+                var timeStamp_Sup = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(timeStamp_Sup);
+
+                // Simple Field (ack_Sup)
+                var ack_Sup = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(ack_Sup);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (alarmUnAck)
+                var alarmUnAck = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(alarmUnAck);
+
+                // Simple Field (locked)
+                var locked = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(locked);
+
+                // Simple Field (inAlarm)
+                var inAlarm = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(inAlarm);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16V16") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (temperature)
+                var temperature = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(temperature);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "N16U32") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (manufacturerCode)
+                var manufacturerCode = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(manufacturerCode);
+
+                // Simple Field (incrementedNumber)
+                var incrementedNumber = io.ReadUint(32);
+                internalMap["Struct"] = new PlcUDINT(incrementedNumber);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "F16F16F16") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (temperatureSetpointComfort)
+                var temperatureSetpointComfort = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointComfort);
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                var temperatureSetpointShiftStandby = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftStandby);
+
+                // Simple Field (temperatureSetpointShiftEco)
+                var temperatureSetpointShiftEco = io.ReadFloat(true, 4, 11);
+                internalMap["Struct"] = new PlcREAL(temperatureSetpointShiftEco);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V8N8N8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (energyDemand)
+                var energyDemand = io.ReadSbyte(8);
+                internalMap["Struct"] = new PlcSINT(energyDemand);
+
+                // Simple Field (hvacControllerMode)
+                var hvacControllerMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacControllerMode);
+
+                // Simple Field (hvacEmergencyMode)
+                var hvacEmergencyMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacEmergencyMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V16V16N8N8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (tempSetpointCooling)
+                var tempSetpointCooling = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(tempSetpointCooling);
+
+                // Simple Field (tempSetpointHeating)
+                var tempSetpointHeating = io.ReadShort(16);
+                internalMap["Struct"] = new PlcINT(tempSetpointHeating);
+
+                // Simple Field (hvacControllerMode)
+                var hvacControllerMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacControllerMode);
+
+                // Simple Field (hvacEmergencyMode)
+                var hvacEmergencyMode = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(hvacEmergencyMode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16U8Scaling") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (timePeriod)
+                var timePeriod = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(timePeriod);
+
+                // Simple Field (percent)
+                var percent = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(percent);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16U8TariffNext") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (delayTime)
+                var delayTime = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(delayTime);
+
+                // Simple Field (tariff)
+                var tariff = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(tariff);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V32N8Z8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (countVal)
+                var countVal = io.ReadInt(32);
+                internalMap["Struct"] = new PlcDINT(countVal);
+
+                // Simple Field (valInfField)
+                var valInfField = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(valInfField);
+
+                // Simple Field (statusOrCommand)
+                var statusOrCommand = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(statusOrCommand);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U16U32U8N8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (manufacturerId)
+                var manufacturerId = io.ReadUshort(16);
+                internalMap["Struct"] = new PlcUINT(manufacturerId);
+
+                // Simple Field (identNumber)
+                var identNumber = io.ReadUint(32);
+                internalMap["Struct"] = new PlcUDINT(identNumber);
+
+                // Simple Field (version)
+                var version = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(version);
+
+                // Simple Field (medium)
+                var medium = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(medium);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "A8A8A8A8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (languageCode)
+                var languageCode = io.ReadString(16);
+                internalMap["Struct"] = new PlcSTRING(languageCode);
+
+                // Simple Field (regionCode)
+                var regionCode = io.ReadString(16);
+                internalMap["Struct"] = new PlcSTRING(regionCode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8U8U8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (red)
+                var red = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(red);
+
+                // Simple Field (green)
+                var green = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(green);
+
+                // Simple Field (blue)
+                var blue = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(blue);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "A8A8Language") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (languageCode)
+                var languageCode = io.ReadString(16);
+                internalMap["Struct"] = new PlcSTRING(languageCode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "A8A8Region") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (regionCode)
+                var regionCode = io.ReadString(16);
+                internalMap["Struct"] = new PlcSTRING(regionCode);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "V32U8B8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (activeElectricalEnergy)
+                var activeElectricalEnergy = io.ReadInt(32);
+                internalMap["Struct"] = new PlcDINT(activeElectricalEnergy);
+
+                // Simple Field (tariff)
+                var tariff = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(tariff);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(6);
+
+                // Simple Field (noTariff)
+                var noTariff = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(noTariff);
+
+                // Simple Field (noActiveElectricalEnergy)
+                var noActiveElectricalEnergy = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(noActiveElectricalEnergy);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B1N3N4") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (deactivationOfPriority)
+                var deactivationOfPriority = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(deactivationOfPriority);
+
+                // Simple Field (priorityLevel)
+                var priorityLevel = io.ReadByte(3);
+                internalMap["Struct"] = new PlcUSINT(priorityLevel);
+
+                // Simple Field (modeLevel)
+                var modeLevel = io.ReadByte(4);
+                internalMap["Struct"] = new PlcUSINT(modeLevel);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B10U6") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(5);
+
+                // Simple Field (convertorError)
+                var convertorError = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(convertorError);
+
+                // Simple Field (ballastFailure)
+                var ballastFailure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(ballastFailure);
+
+                // Simple Field (lampError)
+                var lampError = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(lampError);
+
+                // Simple Field (read)
+                var read = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(read);
+
+                // Simple Field (groupAddress)
+                var groupAddress = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(groupAddress);
+
+                // Simple Field (address)
+                var address = io.ReadByte(6);
+                internalMap["Struct"] = new PlcUSINT(address);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "B2U6") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (sceneActivationInactive)
+                var sceneActivationInactive = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(sceneActivationInactive);
+
+                // Simple Field (storageFunctionDisable)
+                var storageFunctionDisable = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(storageFunctionDisable);
+
+                // Simple Field (sceneNumber)
+                var sceneNumber = io.ReadByte(6);
+                internalMap["Struct"] = new PlcUSINT(sceneNumber);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8r7B1") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (setValue)
+                var setValue = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(setValue);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(7);
+
+                // Simple Field (channelActivationActive)
+                var channelActivationActive = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(channelActivationActive);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8U8B8") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (heightPosition)
+                var heightPosition = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(heightPosition);
+
+                // Simple Field (slatsPosition)
+                var slatsPosition = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(slatsPosition);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(6);
+
+                // Simple Field (validSlatsPos)
+                var validSlatsPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(validSlatsPos);
+
+                // Simple Field (validHeightPos)
+                var validHeightPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(validHeightPos);
+
+                return new PlcStruct(internalMap);
+            } else
+            if (formatName == "U8U8B16") { // Struct
+                var internalMap = new Dictionary<string, IPlcValue>();
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(8);
+
+                // Simple Field (heightPosition)
+                var heightPosition = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(heightPosition);
+
+                // Simple Field (slatsPosition)
+                var slatsPosition = io.ReadByte(8);
+                internalMap["Struct"] = new PlcUSINT(slatsPosition);
+
+                // Simple Field (validSlatsPos)
+                var validSlatsPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(validSlatsPos);
+
+                // Simple Field (validHeightPos)
+                var validHeightPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(validHeightPos);
+
+                // Reserved Field (Just skip the bytes)
+                io.ReadByte(3);
+
+                // Simple Field (failure)
+                var failure = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(failure);
+
+                // Simple Field (localOverride)
+                var localOverride = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(localOverride);
+
+                // Simple Field (locked)
+                var locked = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(locked);
+
+                // Simple Field (forced)
+                var forced = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(forced);
+
+                // Simple Field (weatherAlarm)
+                var weatherAlarm = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(weatherAlarm);
+
+                // Simple Field (targetSPosRestrict)
+                var targetSPosRestrict = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(targetSPosRestrict);
+
+                // Simple Field (targetHPosRestrict)
+                var targetHPosRestrict = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(targetHPosRestrict);
+
+                // Simple Field (driveState)
+                var driveState = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(driveState);
+
+                // Simple Field (lowerPredefPos)
+                var lowerPredefPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(lowerPredefPos);
+
+                // Simple Field (lowerEndPos)
+                var lowerEndPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(lowerEndPos);
+
+                // Simple Field (upperEndPos)
+                var upperEndPos = io.ReadBit();
+                internalMap["Struct"] = new PlcBOOL(upperEndPos);
+
+                return new PlcStruct(internalMap);
+            } 
+            return null;
+        }
+
+        public void Serialize(WriteBuffer io, IPlcValue value, string formatName)
+        {
+            if (formatName == "B1") { // BOOL
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(7, 0x0);
+
+                // Simple Field (value)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "B2") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(6, 0x0);
+
+                // Simple Field (control)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (value)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "B1U3") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x0);
+
+                // Simple Field (control)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (value)
+                io.WriteByte(3, value.GetByte());
+            } else
+            if (formatName == "A8_ASCII") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteString(8, "ASCII", value.GetString());
+            } else
+            if (formatName == "A8_8859_1") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteString(8, "ISO-8859-1", value.GetString());
+            } else
+            if (formatName == "U8") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V8") { // SINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteSbyte(8, value.GetSbyte());
+            } else
+            if (formatName == "B5N3") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x0);
+
+                // Simple Field (a)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (b)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (c)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (d)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (e)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (value)
+                io.WriteSbyte(8, value.GetSbyte());
+            } else
+            if (formatName == "U16") { // UINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteUshort(16, value.GetUshort());
+            } else
+            if (formatName == "V16") { // INT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteShort(16, value.GetShort());
+            } else
+            if (formatName == "F16") { // REAL
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "N3N5r2N6r2N6") { // TIME_OF_DAY
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (day)
+                io.WriteByte(3, value.GetByte());
+
+                // Simple Field (hour)
+                io.WriteByte(5, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (minutes)
+                io.WriteByte(6, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (seconds)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "r3N5r4N4r1U7") { // DATE
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x00);
+
+                // Simple Field (day)
+                io.WriteByte(5, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (month)
+                io.WriteByte(4, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(1, 0x00);
+
+                // Simple Field (year)
+                io.WriteByte(7, value.GetByte());
+            } else
+            if (formatName == "U32") { // UDINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteUint(32, value.GetUint());
+            } else
+            if (formatName == "V32") { // DINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteInt(32, value.GetInt());
+            } else
+            if (formatName == "F32") { // REAL
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteFloat(32, value.GetFloat());
+            } else
+            if (formatName == "U4U4U4U4U4U4B4N4") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (d6)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (d5)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (d4)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (d3)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (d2)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (d1)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (e)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (p)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (d)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (c)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (index)
+                io.WriteByte(4, value.GetByte());
+            } else
+            if (formatName == "A112_ASCII") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteString(112, "ASCII", value.GetString());
+            } else
+            if (formatName == "A112_8859_1") { // STRING
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteString(112, "ISO-8859-1", value.GetString());
+            } else
+            if (formatName == "r2U6") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (value)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "B1r1U6") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (learn)
+                io.WriteBit(value.GetBool());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(1, 0x00);
+
+                // Simple Field (sceneNumber)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "U8r4U4r3U5U3U5r2U6r2U6B16") { // DATE_AND_TIME
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (year)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (month)
+                io.WriteByte(4, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x00);
+
+                // Simple Field (day)
+                io.WriteByte(5, value.GetByte());
+
+                // Simple Field (dayOfWeek)
+                io.WriteByte(3, value.GetByte());
+
+                // Simple Field (hour)
+                io.WriteByte(5, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (minutes)
+                io.WriteByte(6, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (seconds)
+                io.WriteByte(6, value.GetByte());
+
+                // Simple Field (fault)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (workingDay)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noWorkingDay)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noYear)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noMonthAndDay)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noDayOfWeek)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noTime)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (standardSummerTime)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (clockWithSyncSignal)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "N8") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "B8") { // BYTE
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "B16") { // WORD
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteUshort(16, value.GetUshort());
+            } else
+            if (formatName == "U4U4") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (busy)
+                io.WriteByte(4, value.GetByte());
+
+                // Simple Field (nak)
+                io.WriteByte(4, value.GetByte());
+            } else
+            if (formatName == "r1b1U6") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(1, 0x00);
+
+                // Simple Field (sceneActive)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (sceneNumber)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "B32") { // DWORD
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteUint(32, value.GetUint());
+            } else
+            if (formatName == "V64") { // LINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (value)
+                io.WriteLong(64, value.GetLong());
+            } else
+            if (formatName == "B24") { // List
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Array Field (value)
+                for (int i = 0; i < (24); i++) {
+                    io.WriteBit(value.GetIndex(i).GetBool());
+                }
+            } else
+            if (formatName == "N3") { // USINT
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (value)
+                io.WriteByte(3, value.GetByte());
+            } else
+            if (formatName == "B1Z8HeatingOrCoolingZ") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(7, 0x00);
+
+                // Simple Field (heating)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "B1Z8BinaryValueZ") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(7, 0x00);
+
+                // Simple Field (high)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8HvacOperatingMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (hvacOperatingMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8DhwMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (dhwMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8HvacControllingMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (hvacControllingMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8EnableHeatingOrCoolingStage") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (enableHeatingOrCoolingStage)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8BuildingMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (buildingMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8OccupancyMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (occupancyMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "N8Z8EmergencyMode") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (hvacEmergencyMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U8Z8Rel") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (relValue)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U8Z8Counter") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (counterValue)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8TimePeriod") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (timePeriod)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8FlowRate") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (flowRate)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8Counter") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (counterValue)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8ElectricCurrent") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (electricalCurrent)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8Power") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (power)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8AtmPressure") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (atmPressure)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8PercentValue") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (percentValue)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8HvacAirQuality") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (ppmResolution)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8WindSpeed") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (windSpeed)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8SunIntensity") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (sunIntensity)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16Z8HvacAirFlow") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (airFlow)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V8Z8RelSignedValue") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (relSignedValue)
+                io.WriteSbyte(8, value.GetSbyte());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V16Z8DeltaTime") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (deltaTime)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V16Z8RelSignedValue") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (relSignedValue)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16N8HvacModeAndTimeDelay") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (hvacMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16N8DhwModeAndTimeDelay") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (dhwMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16N8OccupancyModeAndTimeDelay") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (occupationMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16N8BuildingModeAndTimeDelay") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (buildingMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U8B8StatusBurnerController") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (actualRelativePower)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (stage2Active)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage1Active)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (actualRelativePowerValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8B8LockingSignal") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (requestedPowerReduction)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(6, 0x00);
+
+                // Simple Field (critical)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (requestedPowerReductionValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8B8BoilerControllerDemandSignal") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (relativeDemand)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(6, 0x00);
+
+                // Simple Field (controlsOperationStage2)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (controlsOperationStage1)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8B8ActuatorPositionDemand") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (actuatorPositionDemand)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (emergencyDemand)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (shiftLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (absoluteLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (actuatorPositionDemandValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8B8ActuatorPositionStatus") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (actualActuatorPosition)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x00);
+
+                // Simple Field (synchronizationMode)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (valveKick)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (callibrationMode)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (positionManuallyOverridden)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8B8StatusLightingActuator") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (lightingLevel)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (localOverride)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (dimming)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (staircaseLightingFunction)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (nightMode)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (forced)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (locked)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (lightingLevelValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16B8HeatProducerManagerStatus") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (tempFlowProdSegmH)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x00);
+
+                // Simple Field (temporarilyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (permanentlyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (switchedOffSummerMode)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (tempFlowProdSegmHValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16B8RoomTemperatureDemand") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (roomTemperatureDemand)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (emergencyDemand)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (shiftLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (absoluteLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (roomTemperatureDemandValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16B8ColdWaterProducerManagerStatus") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (flowTemperatureProdSegmC)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (temporarilyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (permanentlyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (flowTemperatureProdSegmCValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16B8WaterTemperatureControllerStatus") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (actualTemperature)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (controllerWorking)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (actualTemperatureValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16B16") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (flowTemperatureDemand)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (demandFromDhwWhileLegionellaFunctionIsActive)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (emergencyDemandForFrostProtection)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (requestForWaterCirculationInPrimaryDistributionSegment)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (demandFromAuxillaryHeatOrCoolConsumer)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (demandFromVentilation)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (demandForRoomHeatingOrCooling)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (heatDemandFromDhw)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (flowTemperatureDemandIsMin)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (flowTemperatureDemandIsMax)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (shiftLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (absoluteLoadPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (flowTemperatureDemandValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8N8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (energyDemand)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (actualControllerMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V16V16V16RoomTemperature") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointComfort)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointStandby)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointEco)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V16V16V16RoomTemperatureShift") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointShiftComfort)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftEco)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V16V16V16V16RoomTemperature") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointComfort)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointStandby)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointEco)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointBProt)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V16V16V16V16DhwtTemperature") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointLegioProtect)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointNormal)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointReduced)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointFrostProtect)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V16V16V16V16RoomTemperatureShift") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointShiftComfort)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftEco)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftBProt)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V16U8B8Heat") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (flowTemperatureDemand)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (relativePower)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(2, 0x00);
+
+                // Simple Field (boilerEnabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage2Forced)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage2Enabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage1Forced)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage1Enabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (flowTemperatureDemandValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16U8B8ChilledWater") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (chilledWaterFlowTemperatureDemand)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (relativePower)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (chilledWaterPumpEnabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (relativePowerValid)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (chilledWaterFlowTemperatureDemandValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16U8B16Boiler") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (tempBoiler)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (relativePower)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (chimneySweepFunctionActive)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (reducedAvailability)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (powerLimitBoilerReached)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (powerLimitStage1Reached)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage2Enabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (stage1Enabled)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (boilerTemporarilyNotProvidingHeat)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (permanentlyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (boilerSwitchedOffWinterSummerMode)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (boilerFailure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (relativePowerValid)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (tempBoilerValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "V16U8B16Chiller") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (tempChiller)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (relativePower)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x00);
+
+                // Simple Field (reducedAvailability)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (powerLimitChillerReached)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (powerLimitCurrentStageReached)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (permanentlyOff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (chillerFailure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (chillerRunningStatus)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (relativePowerValid)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (tempChillerValid)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U16U8N8B8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (nominalPower)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (relativePowerLimit)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (burnerType)
+                io.WriteSbyte(8, value.GetSbyte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (solidState)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (gas)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (oil)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U5U5U6") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (magicNumber)
+                io.WriteByte(5, value.GetByte());
+
+                // Simple Field (versionNumber)
+                io.WriteByte(5, value.GetByte());
+
+                // Simple Field (revisionNumber)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "V32Z8VolumeLiter") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (volumeLiter)
+                io.WriteInt(32, value.GetInt());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V32Z8FlowRate") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (flowRate)
+                io.WriteInt(32, value.GetInt());
+
+                // Simple Field (statusCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U8N8N8N8B8B8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (logNumber)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (alarmPriority)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (applicationArea)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (errorClass)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(4, 0x00);
+
+                // Simple Field (errorCode_Sup)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (alarmText_Sup)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (timeStamp_Sup)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (ack_Sup)
+                io.WriteBit(value.GetBool());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (alarmUnAck)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (locked)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (inAlarm)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U16V16") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (temperature)
+                io.WriteShort(16, value.GetShort());
+            } else
+            if (formatName == "N16U32") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (manufacturerCode)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (incrementedNumber)
+                io.WriteUint(32, value.GetUint());
+            } else
+            if (formatName == "F16F16F16") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (temperatureSetpointComfort)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftStandby)
+                io.WriteFloat(16, value.GetFloat());
+
+                // Simple Field (temperatureSetpointShiftEco)
+                io.WriteFloat(16, value.GetFloat());
+            } else
+            if (formatName == "V8N8N8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (energyDemand)
+                io.WriteSbyte(8, value.GetSbyte());
+
+                // Simple Field (hvacControllerMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (hvacEmergencyMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V16V16N8N8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (tempSetpointCooling)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (tempSetpointHeating)
+                io.WriteShort(16, value.GetShort());
+
+                // Simple Field (hvacControllerMode)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (hvacEmergencyMode)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16U8Scaling") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (timePeriod)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (percent)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16U8TariffNext") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (delayTime)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (tariff)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "V32N8Z8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (countVal)
+                io.WriteInt(32, value.GetInt());
+
+                // Simple Field (valInfField)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (statusOrCommand)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "U16U32U8N8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (manufacturerId)
+                io.WriteUshort(16, value.GetUshort());
+
+                // Simple Field (identNumber)
+                io.WriteUint(32, value.GetUint());
+
+                // Simple Field (version)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (medium)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "A8A8A8A8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (languageCode)
+                io.WriteString(16, "ASCII", value.GetString());
+
+                // Simple Field (regionCode)
+                io.WriteString(16, "ASCII", value.GetString());
+            } else
+            if (formatName == "U8U8U8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (red)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (green)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (blue)
+                io.WriteByte(8, value.GetByte());
+            } else
+            if (formatName == "A8A8Language") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (languageCode)
+                io.WriteString(16, "ASCII", value.GetString());
+            } else
+            if (formatName == "A8A8Region") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (regionCode)
+                io.WriteString(16, "ASCII", value.GetString());
+            } else
+            if (formatName == "V32U8B8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (activeElectricalEnergy)
+                io.WriteInt(32, value.GetInt());
+
+                // Simple Field (tariff)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(6, 0x00);
+
+                // Simple Field (noTariff)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (noActiveElectricalEnergy)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "B1N3N4") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (deactivationOfPriority)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (priorityLevel)
+                io.WriteByte(3, value.GetByte());
+
+                // Simple Field (modeLevel)
+                io.WriteByte(4, value.GetByte());
+            } else
+            if (formatName == "B10U6") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(5, 0x00);
+
+                // Simple Field (convertorError)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (ballastFailure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (lampError)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (read)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (groupAddress)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (address)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "B2U6") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (sceneActivationInactive)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (storageFunctionDisable)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (sceneNumber)
+                io.WriteByte(6, value.GetByte());
+            } else
+            if (formatName == "U8r7B1") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (setValue)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(7, 0x00);
+
+                // Simple Field (channelActivationActive)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8U8B8") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (heightPosition)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (slatsPosition)
+                io.WriteByte(8, value.GetByte());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(6, 0x00);
+
+                // Simple Field (validSlatsPos)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (validHeightPos)
+                io.WriteBit(value.GetBool());
+            } else
+            if (formatName == "U8U8B16") { // Struct
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(8, 0x0);
+
+                // Simple Field (heightPosition)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (slatsPosition)
+                io.WriteByte(8, value.GetByte());
+
+                // Simple Field (validSlatsPos)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (validHeightPos)
+                io.WriteBit(value.GetBool());
+
+                // Reserved Field (Just skip the bytes)
+                io.WriteByte(3, 0x00);
+
+                // Simple Field (failure)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (localOverride)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (locked)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (forced)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (weatherAlarm)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (targetSPosRestrict)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (targetHPosRestrict)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (driveState)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (lowerPredefPos)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (lowerEndPos)
+                io.WriteBit(value.GetBool());
+
+                // Simple Field (upperEndPos)
+                io.WriteBit(value.GetBool());
+            }         }
+
+    }
+
+}
+
diff --git a/sandbox/plc4net/drivers/knxnetip/generated/testing/assets/protocols/knxnetip/ParserSerializerTestsuite.xml b/sandbox/plc4net/drivers/knxnetip/generated/testing/assets/protocols/knxnetip/ParserSerializerTestsuite.xml
new file mode 100644
index 0000000..2eae8b6
--- /dev/null
+++ b/sandbox/plc4net/drivers/knxnetip/generated/testing/assets/protocols/knxnetip/ParserSerializerTestsuite.xml
@@ -0,0 +1,500 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd" bigEndian="true">
+
+  <name>KNXNet/IP</name>
+
+  <!--testcase>
+    <name>Causes Failure 1</name>
+    <raw>0610042000180404ce002b0703010404025002bab8b838bb</raw>
+    Raw CEMI Frame: bab8b838bb
+    Raw CEMI Frame: ba
+
+    Decoded as Extended Frame Format:
+    group address: true
+    hop count: 3
+    extended frame format: 8 (1 0 0 0)
+    source address: 11/8/56
+
+    <raw>061004200018047ddf002b07030104040207029f9c9c9cdc</raw>
+    Raw CEMI Frame: 9f9c9c9cdc
+    Control Field: 9f
+
+    Differences from normal:
+    Repeat: True
+    Last two reserved bits are true
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
+        <tunnelingRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequestDataBlock">
+          <communicationChannelId>125</communicationChannelId>
+          <sequenceCounter>223</sequenceCounter>
+        </tunnelingRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
+          <additionalInformationLength>7</additionalInformationLength>
+          <additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
+              <frameErrorFlag>false</frameErrorFlag>
+              <bitErrorFlag>false</bitErrorFlag>
+              <parityErrorFlag>false</parityErrorFlag>
+              <unknownFlag>false</unknownFlag>
+              <lostFlag>false</lostFlag>
+              <sequenceNumber>4</sequenceNumber>
+            </additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
+              <relativeTimestamp className="org.apache.plc4x.java.knxnetip.readwrite.RelativeTimestamp">
+                <timestamp>1794</timestamp>
+              </relativeTimestamp>
+            </additionalInformation>
+          </additionalInformation>
+          <cemiFrame className="org.apache.plc4x.java.knxnetip.readwrite.CEMIFramePollingData">
+            <doNotRepeat>false</doNotRepeat>
+            <priority>LOW</priority>
+            <errorFlag>true</errorFlag>
+          </cemiFrame>
+        </cemi>
+      </TunnelingRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Causes Failure 2</name>
+    <raw>0610042000180401c2002b0703010304025601bab8b838bb</raw>
+    Raw CEMI Frame: bab8b838bb
+    Control Field: ba
+    First of the last two reserved bits is true
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
+        <tunnelingRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequestDataBlock">
+          <communicationChannelId>1</communicationChannelId>
+          <sequenceCounter>194</sequenceCounter>
+        </tunnelingRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
+          <additionalInformationLength>7</additionalInformationLength>
+          <additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
+              <frameErrorFlag>false</frameErrorFlag>
+              <bitErrorFlag>false</bitErrorFlag>
+              <parityErrorFlag>false</parityErrorFlag>
+              <unknownFlag>false</unknownFlag>
+              <lostFlag>false</lostFlag>
+              <sequenceNumber>3</sequenceNumber>
+            </additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
+              <relativeTimestamp className="org.apache.plc4x.java.knxnetip.readwrite.RelativeTimestamp">
+                <timestamp>22017</timestamp>
+              </relativeTimestamp>
+            </additionalInformation>
+          </additionalInformation>
+          <cemiFrame className="org.apache.plc4x.java.knxnetip.readwrite.CEMIFramePollingData">
+            <doNotRepeat>true</doNotRepeat>
+            <priority>URGENT</priority>
+            <errorFlag>false</errorFlag>
+          </cemiFrame>
+        </cemi>
+      </TunnelingRequest>
+    </xml>
+  </testcase-->
+
+  <testcase>
+    <name>Search Request</name>
+    <raw>06100201000e0801c0a82a46ef8e</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <SearchRequest className="org.apache.plc4x.java.knxnetip.readwrite.SearchRequest">
+        <hpaiIDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>61326</ipPort>
+        </hpaiIDiscoveryEndpoint>
+      </SearchRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Search Response</name>
+    <raw>06100202004c0801c0a82a0b0e5736010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <SearchResponse className="org.apache.plc4x.java.knxnetip.readwrite.SearchResponse">
+        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqCw==</addr>
+          </ipAddress>
+          <ipPort>3671</ipPort>
+        </hpaiControlEndpoint>
+        <dibDeviceInfo className="org.apache.plc4x.java.knxnetip.readwrite.DIBDeviceInfo">
+          <descriptionType>1</descriptionType>
+          <knxMedium>MEDIUM_TP1</knxMedium>
+          <deviceStatus className="org.apache.plc4x.java.knxnetip.readwrite.DeviceStatus">
+            <programMode>false</programMode>
+          </deviceStatus>
+          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
+            <mainGroup>15</mainGroup>
+            <middleGroup>15</middleGroup>
+            <subGroup>255</subGroup>
+          </knxAddress>
+          <projectInstallationIdentifier className="org.apache.plc4x.java.knxnetip.readwrite.ProjectInstallationIdentifier">
+            <projectNumber>0</projectNumber>
+            <installationNumber>0</installationNumber>
+          </projectInstallationIdentifier>
+          <knxNetIpDeviceSerialNumber>AAgtQJhS</knxNetIpDeviceSerialNumber>
+          <knxNetIpDeviceMulticastAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>4AAXDA==</addr>
+          </knxNetIpDeviceMulticastAddress>
+          <knxNetIpDeviceMacAddress className="org.apache.plc4x.java.knxnetip.readwrite.MACAddress">
+            <addr>AAqzJ1U2</addr>
+          </knxNetIpDeviceMacAddress>
+          <deviceFriendlyName>R2lyYSBLTlgvSVAtU2Nobml0dHN0ZWxsZQAAAAAA</deviceFriendlyName>
+        </dibDeviceInfo>
+        <dibSuppSvcFamilies className="org.apache.plc4x.java.knxnetip.readwrite.DIBSuppSvcFamilies">
+          <descriptionType>2</descriptionType>
+          <serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
+              <version>1</version>
+            </serviceIds>
+          </serviceIds>
+        </dibSuppSvcFamilies>
+      </SearchResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Description Request</name>
+    <raw>06100203000e0801000000000000</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DescriptionRequest className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionRequest">
+        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>AAAAAA==</addr>
+          </ipAddress>
+          <ipPort>0</ipPort>
+        </hpaiControlEndpoint>
+      </DescriptionRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Description Response</name>
+    <raw>06100204004436010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DescriptionResponse className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionResponse">
+        <dibDeviceInfo className="org.apache.plc4x.java.knxnetip.readwrite.DIBDeviceInfo">
+          <descriptionType>1</descriptionType>
+          <knxMedium>MEDIUM_TP1</knxMedium>
+          <deviceStatus className="org.apache.plc4x.java.knxnetip.readwrite.DeviceStatus">
+            <programMode>false</programMode>
+          </deviceStatus>
+          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
+            <mainGroup>15</mainGroup>
+            <middleGroup>15</middleGroup>
+            <subGroup>255</subGroup>
+          </knxAddress>
+          <projectInstallationIdentifier className="org.apache.plc4x.java.knxnetip.readwrite.ProjectInstallationIdentifier">
+            <projectNumber>0</projectNumber>
+            <installationNumber>0</installationNumber>
+          </projectInstallationIdentifier>
+          <knxNetIpDeviceSerialNumber>AAgtQJhS</knxNetIpDeviceSerialNumber>
+          <knxNetIpDeviceMulticastAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>4AAXDA==</addr>
+          </knxNetIpDeviceMulticastAddress>
+          <knxNetIpDeviceMacAddress className="org.apache.plc4x.java.knxnetip.readwrite.MACAddress">
+            <addr>AAqzJ1U2</addr>
+          </knxNetIpDeviceMacAddress>
+          <deviceFriendlyName>R2lyYSBLTlgvSVAtU2Nobml0dHN0ZWxsZQAAAAAA</deviceFriendlyName>
+        </dibDeviceInfo>
+        <dibSuppSvcFamilies className="org.apache.plc4x.java.knxnetip.readwrite.DIBSuppSvcFamilies">
+          <descriptionType>2</descriptionType>
+          <serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
+              <version>1</version>
+            </serviceIds>
+          </serviceIds>
+        </dibSuppSvcFamilies>
+      </DescriptionResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connect Request</name>
+    <raw>06100205001a0801c0a82a46f4310801c0a82a46f43204040200</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
+        <hpaiDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiDiscoveryEndpoint>
+        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>62514</ipPort>
+        </hpaiDataEndpoint>
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationTunnelConnection">
+          <knxLayer>TUNNEL_LINK_LAYER</knxLayer>
+        </connectionRequestInformation>
+      </ConnectionRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connect Response</name>
+    <raw>06100206001466000801c0a82a0b0e5704041101</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <ConnectionResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>NO_ERROR</status>
+        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqCw==</addr>
+          </ipAddress>
+          <ipPort>3671</ipPort>
+        </hpaiDataEndpoint>
+        <connectionResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponseDataBlockTunnelConnection">
+          <knxAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
+            <mainGroup>1</mainGroup>
+            <middleGroup>1</middleGroup>
+            <subGroup>1</subGroup>
+          </knxAddress>
+        </connectionResponseDataBlock>
+      </ConnectionResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connection State Request</name>
+    <raw>06100207001066000801c0a82a46f431</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <ConnectionStateRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateRequest">
+        <communicationChannelId>102</communicationChannelId>
+        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiControlEndpoint>
+      </ConnectionStateRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connection State Response</name>
+    <raw>0610020800086600</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <ConnectionStateResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>NO_ERROR</status>
+      </ConnectionStateResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Device Configuration Request</name>
+    <raw>06100310001104670000fc000001531001</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DeviceConfigurationRequest className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequest">
+        <deviceConfigurationRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequestDataBlock">
+          <communicationChannelId>103</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+        </deviceConfigurationRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIMPropReadReq">
+          <interfaceObjectType>0</interfaceObjectType>
+          <objectInstance>1</objectInstance>
+          <propertyId>83</propertyId>
+          <numberOfElements>1</numberOfElements>
+          <startIndex>1</startIndex>
+        </cemi>
+      </DeviceConfigurationRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Device Configuration Ack</name>
+    <raw>06100311000a04670000</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DeviceConfigurationAck className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAck">
+        <deviceConfigurationAckDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAckDataBlock">
+          <communicationChannelId>103</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+          <status>NO_ERROR</status>
+        </deviceConfigurationAckDataBlock>
+      </DeviceConfigurationAck>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Disconnect Request</name>
+    <raw>06100209001067000801c0a82a46f431</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DisconnectRequest className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectRequest">
+        <communicationChannelId>103</communicationChannelId>
+        <hpaiControlEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIControlEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiControlEndpoint>
+      </DisconnectRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Disconnect Response</name>
+    <raw>0610020a00086600</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <DisconnectResponse className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>NO_ERROR</status>
+      </DisconnectResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Tunneling Request</name>
+    <raw>06100420001c046b00002b0703010504024502bc360a1e0ce100810d</raw>
+    <!--
+    Raw CEMI Frame: bc360a1e0ce100810d
+    Control Field: bc
+    -->
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
+        <tunnelingRequestDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequestDataBlock">
+          <communicationChannelId>107</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+        </tunnelingRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIBusmonInd">
+          <additionalInformationLength>7</additionalInformationLength>
+          <additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
+              <frameErrorFlag>false</frameErrorFlag>
+              <bitErrorFlag>false</bitErrorFlag>
+              <parityErrorFlag>false</parityErrorFlag>
+              <unknownFlag>false</unknownFlag>
+              <lostFlag>false</lostFlag>
+              <sequenceNumber>5</sequenceNumber>
+            </additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
+              <relativeTimestamp className="org.apache.plc4x.java.knxnetip.readwrite.RelativeTimestamp">
+                <timestamp>17666</timestamp>
+              </relativeTimestamp>
+            </additionalInformation>
+          </additionalInformation>
+          <cemiFrame className="org.apache.plc4x.java.knxnetip.readwrite.CEMIFrameData">
+            <repeated>true</repeated>
+            <priority>LOW</priority>
+            <acknowledgeRequested>false</acknowledgeRequested>
+            <errorFlag>false</errorFlag>
+            <sourceAddress className="org.apache.plc4x.java.knxnetip.readwrite.KnxAddress">
+              <mainGroup>3</mainGroup>
+              <middleGroup>6</middleGroup>
+              <subGroup>10</subGroup>
+            </sourceAddress>
+            <destinationAddress>Hgw=</destinationAddress>
+            <groupAddress>true</groupAddress>
+            <hopCount>6</hopCount>
+            <dataLength>1</dataLength>
+            <tcpi>UNNUMBERED_DATA_PACKET</tcpi>
+            <counter>0</counter>
+            <apci>GROUP_VALUE_WRITE_PDU</apci>
+            <dataFirstByte>1</dataFirstByte>
+            <data></data>
+            <crc>13</crc>
+          </cemiFrame>
+        </cemi>
+      </TunnelingRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Tunneling Response</name>
+    <raw>06100421000a046b0000</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <TunnelingResponse className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponse">
+        <tunnelingResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponseDataBlock">
+          <communicationChannelId>107</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+          <status>NO_ERROR</status>
+        </tunnelingResponseDataBlock>
+      </TunnelingResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Default</name>
+    <raw>0610020500180801c0a82a46c4090801c0a82a46c40a0203</raw>
+    <root-type>KnxNetIpMessage</root-type>
+    <xml>
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
+        <hpaiDiscoveryEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDiscoveryEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>50185</ipPort>
+        </hpaiDiscoveryEndpoint>
+        <hpaiDataEndpoint className="org.apache.plc4x.java.knxnetip.readwrite.HPAIDataEndpoint">
+          <hostProtocolCode>IPV4_UDP</hostProtocolCode>
+          <ipAddress className="org.apache.plc4x.java.knxnetip.readwrite.IPAddress">
+            <addr>wKgqRg==</addr>
+          </ipAddress>
+          <ipPort>50186</ipPort>
+        </hpaiDataEndpoint>
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationDeviceManagement"/>
+      </ConnectionRequest>
+    </xml>
+  </testcase>
+
+</test:testsuite>
\ No newline at end of file
diff --git a/sandbox/plc4net/api/api.csproj b/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
similarity index 70%
copy from sandbox/plc4net/api/api.csproj
copy to sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
index eb00812..e783193 100644
--- a/sandbox/plc4net/api/api.csproj
+++ b/sandbox/plc4net/drivers/knxnetip/plc4net-driver-knxproj.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -22,6 +22,15 @@
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <RootNamespace>org.apache.plc4net</RootNamespace>
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+    <Authors>Apache PLC4X</Authors>
+    <Copyright>The Apache Software Foundation</Copyright>
+    <PackageProjectUrl>https://plc4x.apache.org</PackageProjectUrl>
   </PropertyGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\..\api\plc4net-api.csproj" />
+    <ProjectReference Include="..\..\spi\plc4net-spi.csproj" />
+  </ItemGroup>
+
 </Project>
diff --git a/sandbox/plc4net/plc4net.sln b/sandbox/plc4net/plc4net.sln
index a872a2d..8e4ebe1 100644
--- a/sandbox/plc4net/plc4net.sln
+++ b/sandbox/plc4net/plc4net.sln
@@ -19,10 +19,13 @@
 # under the License.
 #
 
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28803.156
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "api", "plc4net\plc4net.csproj", "{343770DC-ECE5-4131-9066-A09C120BB3D9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plc4net-api", "api\plc4net-api.csproj", "{7906988A-C7CA-4886-A343-EBC17C0BAB59}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plc4net-spi", "spi\plc4net-spi.csproj", "{A92DD9F9-1688-4E70-A95E-709E12DBB8C5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "drivers", "drivers", "{35D8C56A-A721-46B3-A32C-71FCF212E85D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "plc4net-driver-knxproj", "drivers\knxnetip\plc4net-driver-knxproj.csproj", "{640E582A-68DF-4E51-B019-AE5774F31B54}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -30,15 +33,20 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{343770DC-ECE5-4131-9066-A09C120BB3D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{343770DC-ECE5-4131-9066-A09C120BB3D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{343770DC-ECE5-4131-9066-A09C120BB3D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{343770DC-ECE5-4131-9066-A09C120BB3D9}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
+		{7906988A-C7CA-4886-A343-EBC17C0BAB59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7906988A-C7CA-4886-A343-EBC17C0BAB59}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7906988A-C7CA-4886-A343-EBC17C0BAB59}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7906988A-C7CA-4886-A343-EBC17C0BAB59}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A92DD9F9-1688-4E70-A95E-709E12DBB8C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A92DD9F9-1688-4E70-A95E-709E12DBB8C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A92DD9F9-1688-4E70-A95E-709E12DBB8C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A92DD9F9-1688-4E70-A95E-709E12DBB8C5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{640E582A-68DF-4E51-B019-AE5774F31B54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{640E582A-68DF-4E51-B019-AE5774F31B54}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{640E582A-68DF-4E51-B019-AE5774F31B54}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{640E582A-68DF-4E51-B019-AE5774F31B54}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {DCB0DDB3-E6AA-4801-844E-5C71EB50CB1B}
+	GlobalSection(NestedProjects) = preSolution
+		{640E582A-68DF-4E51-B019-AE5774F31B54} = {35D8C56A-A721-46B3-A32C-71FCF212E85D}
 	EndGlobalSection
 EndGlobal
diff --git a/sandbox/plc4net/pom.xml b/sandbox/plc4net/pom.xml
index ab7bdb8..418a489 100644
--- a/sandbox/plc4net/pom.xml
+++ b/sandbox/plc4net/pom.xml
@@ -38,9 +38,103 @@
     <sonar.language>c#</sonar.language>
   </properties-->
 
-  <modules>
-    <module>api</module>
-    <module>plc4net.driver</module>
-  </modules>
+  <build>
+    <plugins>
+      <!-- Copy the test-resources in here -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack-protocol-test-suites</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.apache.plc4x</groupId>
+                  <artifactId>plc4x-protocols-knxnetip</artifactId>
+                  <classifier>tests</classifier>
+                  <type>test-jar</type>
+                  <outputDirectory>${project.basedir}/drivers/knxnetip/generated/testing/assets</outputDirectory>
+                  <includes>**/*.xml</includes>
+                  <excludes>META-INF/**,org/**</excludes>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!--
+        Generate the driver code.
+      -->
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-driver-knxnetip</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>knxnetip</protocolName>
+              <languageName>C#</languageName>
+              <outputFlavor>read-write</outputFlavor>
+              <outputDir>${project.basedir}/drivers/knxnetip/generated/sources</outputDir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Build the project -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>dotnet-build</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>dotnet</executable>
+              <workingDirectory>${project.basedir}</workingDirectory>
+              <arguments>
+                <argument>build</argument>
+                <argument>plc4net.sln</argument>
+                <argument>--configuration=Debug</argument>
+                <argument>--output=${project.build.directory}/build</argument>
+                <argument>-p:Version=${project.version}</argument>
+              </arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-build-utils-language-cs</artifactId>
+      <version>0.8.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-knxnetip</artifactId>
+      <version>0.8.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/sandbox/plc4net/api/api.csproj b/sandbox/plc4net/spi/plc4net-spi.csproj
similarity index 57%
rename from sandbox/plc4net/api/api.csproj
rename to sandbox/plc4net/spi/plc4net-spi.csproj
index eb00812..26090c5 100644
--- a/sandbox/plc4net/api/api.csproj
+++ b/sandbox/plc4net/spi/plc4net-spi.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -19,9 +19,21 @@
 -->
 <Project Sdk="Microsoft.NET.Sdk">
 
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <RootNamespace>org.apache.plc4net</RootNamespace>
-  </PropertyGroup>
+    <PropertyGroup>
+        <TargetFramework>netstandard2.0</TargetFramework>
+        <RootNamespace>org.apache.plc4net</RootNamespace>
+        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+        <Authors>Apache PLC4X</Authors>
+        <Copyright>The Apache Software Foundation</Copyright>
+        <PackageProjectUrl>https://plc4x.apache.org</PackageProjectUrl>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\api\plc4net-api.csproj" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Ayx.BitIO" Version="1.0.0" />
+    </ItemGroup>
 
 </Project>
diff --git a/sandbox/plc4net/spi/spi/generation/ReadBuffer.cs b/sandbox/plc4net/spi/spi/generation/ReadBuffer.cs
new file mode 100644
index 0000000..a14ff8c
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/generation/ReadBuffer.cs
@@ -0,0 +1,203 @@
+//
+// 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.
+//
+
+using System;
+using System.Text;
+using Ayx.BitIO;
+
+namespace org.apache.plc4net.spi.generation
+{
+    
+    public class ReadBuffer
+    {
+        private readonly byte[] _data;
+        private readonly BitReader _reader;
+
+        public ReadBuffer(byte[] data)
+        {
+            this._data = data;
+            _reader = new BitReader(data);
+        }
+
+        public void Reset()
+        {
+            _reader.Position = 0;
+        }
+
+        public int GetPos()
+        {
+            return _reader.Position;
+        }
+
+        public byte[] GetBytes()
+        {
+            return _data;
+        }
+    
+        public int GetTotalBytes() 
+        {
+            return _data.Length;
+        }
+
+        public bool HasMore(int bitLength)
+        {
+            return bitLength < _reader.Remain;
+        }
+
+        public byte PeekByte(int offset)
+        {
+            return _data[(_reader.Position / 8) + offset];
+        }
+
+        public bool ReadBit()
+        {
+            return _reader.ReadBool();
+        }
+
+        public byte ReadByte(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 8)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (byte) _reader.ReadInt(0, bitLength);
+        }
+        
+        public ushort ReadUshort(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 16)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (ushort) _reader.ReadInt(0, bitLength);
+        }
+
+        public uint ReadUint(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 32)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (uint) _reader.ReadInt(0, bitLength);
+        }
+
+        public ulong ReadUlong(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 64)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+
+            ulong firstInt = 0;
+            if (bitLength > 32)
+            {
+                firstInt = (ulong) _reader.ReadInt(0, bitLength - 32) << 32;
+            }
+            return firstInt | (ulong) _reader.ReadInt(0, bitLength);
+        }
+
+        public sbyte ReadSbyte(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 8)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (sbyte) _reader.ReadInt(0, bitLength);
+        }
+        
+        public short ReadShort(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 16)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (short) _reader.ReadInt(0, bitLength);
+        }
+
+        public int ReadInt(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 32)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (int) _reader.ReadInt(0, bitLength);
+        }
+
+        public long ReadLong(int bitLength)
+        {
+            if ((bitLength < 0) || (bitLength > 64)) 
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+
+            long firstInt = 0;
+            if (bitLength > 32)
+            {
+                firstInt = (long) _reader.ReadInt(0, bitLength - 32) << 32;
+            }
+            return firstInt | (long) _reader.ReadInt(0, bitLength);
+        }
+
+        public float ReadFloat(bool signed, int exponentBitLength, int mantissaBitLength)
+        {
+            if (signed && exponentBitLength == 8 && mantissaBitLength == 23)
+            {
+                return Convert.ToSingle(ReadInt(32));
+            }
+            // This is the format as described in the KNX spec ... it's not a real half precision floating point.
+            if (signed && exponentBitLength == 4 && mantissaBitLength == 11)
+            {
+                bool sign = true;
+                if (signed) {
+                    sign = _reader.ReadBool();
+                }
+
+                var exp = _reader.ReadInt(exponentBitLength);
+                var mantissa = _reader.ReadInt(mantissaBitLength);
+                // In the mantissa notation actually the first bit is omitted, we need to add it back
+                var f = 0.01 * mantissa * Math.Pow(2, exp);
+                if (sign)
+                {
+                    return (float) f * -1;
+                }
+                return (float) f;
+            }
+            throw new NotImplementedException("This encoding is currently not supported");
+        }
+
+        public double ReadDouble(bool signed, int exponentBitLength, int mantissaBitLength)
+        {
+            if (signed && exponentBitLength == 8 && mantissaBitLength == 23)
+            {
+                return Convert.ToDouble(ReadInt(32));
+            }
+            if (signed && exponentBitLength == 11 && mantissaBitLength == 52)
+            {
+                return Convert.ToDouble(ReadLong(64));
+            }
+            throw new NotImplementedException("This encoding is currently not supported");
+        }
+
+        public string ReadString(int bitLength, Encoding encoding)
+        {
+            return "";
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/generation/WriteBuffer.cs b/sandbox/plc4net/spi/spi/generation/WriteBuffer.cs
new file mode 100644
index 0000000..5f4b3b1
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/generation/WriteBuffer.cs
@@ -0,0 +1,89 @@
+//
+// 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.
+//
+
+namespace org.apache.plc4net.spi.generation
+{
+    public class WriteBuffer
+    {
+        
+        public int GetPos()
+        {
+            return 0;
+        }
+
+        public byte[] GetBytes()
+        {
+            return null;
+        }
+    
+        public int GetTotalBytes() 
+        {
+            return 0;
+        }
+
+        public void WriteBit(bool value)
+        {
+        }
+
+        public void WriteByte(int bitLength, byte value)
+        {
+        }
+        
+        public void WriteUshort(int bitLength, ushort value)
+        {
+        }
+
+        public void WriteUint(int bitLength, uint value)
+        {
+        }
+
+        public void WriteUlong(int bitLength, ulong value)
+        {
+        }
+
+        public void WriteSbyte(int bitLength, sbyte value)
+        {
+        }
+        
+        public void WriteShort(int bitLength, short value)
+        {
+        }
+
+        public void WriteInt(int bitLength, int value)
+        {
+        }
+
+        public void WriteLong(int bitLength, long value)
+        {
+        }
+
+        public void WriteFloat(int bitLength, float value)
+        {
+        }
+
+        public void WriteDouble(int bitLength, double value)
+        {
+        }
+
+        public void WriteString(int bitLength, string encoding, string value)
+        {
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcBOOL.cs b/sandbox/plc4net/spi/spi/model/values/PlcBOOL.cs
new file mode 100644
index 0000000..a3a11ad
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcBOOL.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcBOOL : PlcSimpleValueAdapter
+    {
+        private bool value;
+        
+        public PlcBOOL(bool value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcBYTE.cs b/sandbox/plc4net/spi/spi/model/values/PlcBYTE.cs
new file mode 100644
index 0000000..5c3d26e
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcBYTE.cs
@@ -0,0 +1,32 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcBYTE : PlcBitString
+    {
+        private byte value;
+        public PlcBYTE(byte value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcBitString.cs b/sandbox/plc4net/spi/spi/model/values/PlcBitString.cs
new file mode 100644
index 0000000..4bcbcba
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcBitString.cs
@@ -0,0 +1,7 @@
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcBitString : PlcValueAdapter
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcCHAR.cs b/sandbox/plc4net/spi/spi/model/values/PlcCHAR.cs
new file mode 100644
index 0000000..958bb0f
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcCHAR.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcCHAR : PlcSimpleValueAdapter
+    {
+        private char value;
+        
+        public PlcCHAR(char value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcDATE.cs b/sandbox/plc4net/spi/spi/model/values/PlcDATE.cs
new file mode 100644
index 0000000..d51b3c4
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcDATE.cs
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+using System;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcDATE : PlcValueAdapter
+    {
+        private DateTime value;
+        
+        public PlcDATE(DateTime value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcDATE_AND_TIME.cs b/sandbox/plc4net/spi/spi/model/values/PlcDATE_AND_TIME.cs
new file mode 100644
index 0000000..1a9b528
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcDATE_AND_TIME.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using System;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcDATE_AND_TIME : PlcValueAdapter
+    {
+        private DateTime value;
+        public PlcDATE_AND_TIME(DateTime value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcDINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcDINT.cs
new file mode 100644
index 0000000..948b114
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcDINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcDINT : SimpleNumericValueAdapter<int>
+    {
+        public PlcDINT(int value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcDWORD.cs b/sandbox/plc4net/spi/spi/model/values/PlcDWORD.cs
new file mode 100644
index 0000000..dad1973
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcDWORD.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcDWORD : PlcBitString
+    {
+        private uint value;
+        
+        public PlcDWORD(uint value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcINT.cs
new file mode 100644
index 0000000..1dfee20
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcINT : SimpleNumericValueAdapter<short>
+    {
+        public PlcINT(short value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcLINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcLINT.cs
new file mode 100644
index 0000000..0bdfdd8
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcLINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcLINT : SimpleNumericValueAdapter<long>
+    {
+        public PlcLINT(long value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcLREAL.cs b/sandbox/plc4net/spi/spi/model/values/PlcLREAL.cs
new file mode 100644
index 0000000..91dc4b5
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcLREAL.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcLREAL : SimpleNumericValueAdapter<double>
+    {
+        public PlcLREAL(double value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcLTIME.cs b/sandbox/plc4net/spi/spi/model/values/PlcLTIME.cs
new file mode 100644
index 0000000..cfd3b7c
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcLTIME.cs
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+using System;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcLTIME : PlcSimpleValueAdapter
+    {
+        private DateTime value;
+        
+        public PlcLTIME(DateTime value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcLWORD.cs b/sandbox/plc4net/spi/spi/model/values/PlcLWORD.cs
new file mode 100644
index 0000000..bfe68af
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcLWORD.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcLWORD : PlcBitString
+    {
+        private ulong value;
+        
+        public PlcLWORD(ulong value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcNULL.cs b/sandbox/plc4net/spi/spi/model/values/PlcNULL.cs
new file mode 100644
index 0000000..1822fd1
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcNULL.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcNULL : PlcValueAdapter
+    {
+        public PlcNULL()
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcPlcList.cs b/sandbox/plc4net/spi/spi/model/values/PlcPlcList.cs
new file mode 100644
index 0000000..1930a60
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcPlcList.cs
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+using System.Collections.Generic;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcList : PlcValueAdapter
+    {
+        private List<IPlcValue> values;
+        
+        public PlcList(List<IPlcValue> values)
+        {
+            this.values = values;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcREAL.cs b/sandbox/plc4net/spi/spi/model/values/PlcREAL.cs
new file mode 100644
index 0000000..f3c1976
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcREAL.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcREAL : SimpleNumericValueAdapter<float>
+    {
+        public PlcREAL(float value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcSINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcSINT.cs
new file mode 100644
index 0000000..c04fcef
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcSINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcSINT : SimpleNumericValueAdapter<sbyte>
+    {
+        public PlcSINT(sbyte value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcSTRING.cs b/sandbox/plc4net/spi/spi/model/values/PlcSTRING.cs
new file mode 100644
index 0000000..be41810
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcSTRING.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcSTRING : PlcSimpleValueAdapter
+    {
+        private string value;
+        
+        public PlcSTRING(string value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcSimpleNumericValueAdapter.cs b/sandbox/plc4net/spi/spi/model/values/PlcSimpleNumericValueAdapter.cs
new file mode 100644
index 0000000..2f0cbba
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcSimpleNumericValueAdapter.cs
@@ -0,0 +1,175 @@
+using System;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public abstract class SimpleNumericValueAdapter<T> : PlcSimpleValueAdapter where T : IComparable
+    {
+        private IComparable value;
+
+        public SimpleNumericValueAdapter(IComparable value)
+        {
+            this.value = value;
+        }
+        
+        public new bool IsBool()
+        {
+            return true;
+        }
+        
+        public new bool GetBool()
+        {
+            return value.CompareTo(0) != 0;
+        }
+        
+        public new bool IsByte()
+        {
+            return (value.CompareTo(byte.MinValue) >= 0) && (value.CompareTo(byte.MaxValue) <= 0);
+        }
+
+        public new byte GetByte()
+        {
+            if (!IsByte())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (byte) value;
+        }
+
+        public new bool IsUshort()
+        {
+            return (value.CompareTo(ushort.MinValue) >= 0) && (value.CompareTo(ushort.MaxValue) <= 0);
+        }
+
+        public new ushort GetUshort()
+        {
+            if (!IsUshort())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (ushort) value;
+        }
+
+        public new bool IsUint()
+        {
+            return (value.CompareTo(uint.MinValue) >= 0) && (value.CompareTo(uint.MaxValue) <= 0);
+        }
+
+        public new uint GetUint()
+        {
+            if (!IsUint())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (uint) value;
+        }
+
+        public new bool IsUlong()
+        {
+            return (value.CompareTo(ulong.MinValue) >= 0) && (value.CompareTo(ulong.MaxValue) <= 0);
+        }
+
+        public new ulong GetUlong()
+        {
+            if (!IsUlong())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (ulong) value;
+        }
+
+        public new bool IsSbyte()
+        {
+            return (value.CompareTo(sbyte.MinValue) >= 0) && (value.CompareTo(sbyte.MaxValue) <= 0);
+        }
+
+        public new sbyte GetSbyte()
+        {
+            if (!IsSbyte())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (sbyte) value;
+        }
+
+        public new bool IsShort()
+        {
+            return (value.CompareTo(short.MinValue) >= 0) && (value.CompareTo(short.MaxValue) <= 0);
+        }
+
+        public new short GetShort()
+        {
+            if (!IsShort())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (short) value;
+        }
+
+        public new bool IsInt()
+        {
+            return (value.CompareTo(int.MinValue) >= 0) && (value.CompareTo(int.MaxValue) <= 0);
+        }
+
+        public new int GetInt()
+        {
+            if (!IsInt())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (int) value;
+        }
+
+        public new bool IsLong()
+        {
+            return (value.CompareTo(long.MinValue) >= 0) && (value.CompareTo(long.MaxValue) <= 0);
+        }
+
+        public new long GetLong()
+        {
+            if (!IsLong())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (long) value;
+        }
+
+        public new bool IsFloat()
+        {
+            return (value.CompareTo(-float.MaxValue) >= 0) && (value.CompareTo(float.MaxValue) <= 0);
+        }
+
+        public new float GetFloat()
+        {
+            if (!IsFloat())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (float) value;
+        }
+
+        public new bool IsDouble()
+        {
+            return (value.CompareTo(-double.MaxValue) >= 0) && (value.CompareTo(double.MaxValue) <= 0);
+        }
+
+        public new double GetDouble()
+        {
+            if (!IsDouble())
+            {
+                throw new ArgumentOutOfRangeException();
+            }
+            return (double) value;
+        }
+
+        public new bool IsString()
+        {
+            return true;
+        }
+
+        public new String GetString()
+        {
+            return value.ToString();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcSimpleValueAdapter.cs b/sandbox/plc4net/spi/spi/model/values/PlcSimpleValueAdapter.cs
new file mode 100644
index 0000000..52a64b9
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcSimpleValueAdapter.cs
@@ -0,0 +1,17 @@
+namespace org.apache.plc4net.spi.model.values
+{
+    public abstract class PlcSimpleValueAdapter : PlcValueAdapter
+    {
+       
+        public  bool IsSimple()
+        {
+            return true;
+        }
+
+        public int GetLength()
+        {
+            return 1;
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcStruct.cs b/sandbox/plc4net/spi/spi/model/values/PlcStruct.cs
new file mode 100644
index 0000000..206fac3
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcStruct.cs
@@ -0,0 +1,37 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+using System.Collections.Generic;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    
+    public class PlcStruct : PlcValueAdapter
+    {
+        private Dictionary<string, IPlcValue> values;
+        
+        public PlcStruct(Dictionary<string, IPlcValue> values)
+        {
+            this.values = values;
+        }
+        
+    }
+    
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcTIME _OF_DAY.cs b/sandbox/plc4net/spi/spi/model/values/PlcTIME _OF_DAY.cs
new file mode 100644
index 0000000..2c3c67a
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcTIME _OF_DAY.cs	
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+using System;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcTIME_OF_DAY : PlcSimpleValueAdapter
+    {
+        private DateTime value;
+        
+        public PlcTIME_OF_DAY(DateTime value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcTIME.cs b/sandbox/plc4net/spi/spi/model/values/PlcTIME.cs
new file mode 100644
index 0000000..0d78c57
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcTIME.cs
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+using System;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcTIME : PlcSimpleValueAdapter
+    {
+        private DateTime value;
+         
+        public PlcTIME(DateTime value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcUDINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcUDINT.cs
new file mode 100644
index 0000000..2cd4e00
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcUDINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcUDINT : SimpleNumericValueAdapter<uint>
+    {
+        public PlcUDINT(uint value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcUINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcUINT.cs
new file mode 100644
index 0000000..e06e9e2
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcUINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcUINT : SimpleNumericValueAdapter<ushort>
+    {
+        public PlcUINT(ushort value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcULINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcULINT.cs
new file mode 100644
index 0000000..a281066
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcULINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcULINT : SimpleNumericValueAdapter<ulong>
+    {
+        public PlcULINT(ulong value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcUSINT.cs b/sandbox/plc4net/spi/spi/model/values/PlcUSINT.cs
new file mode 100644
index 0000000..c1b031d
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcUSINT.cs
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcUSINT : SimpleNumericValueAdapter<byte>
+    {
+        public PlcUSINT(byte value) : base(value)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcValueAdapter.cs b/sandbox/plc4net/spi/spi/model/values/PlcValueAdapter.cs
new file mode 100644
index 0000000..f5227f6
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcValueAdapter.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Collections.Generic;
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public abstract class PlcValueAdapter : IPlcValue
+    {
+        public bool IsSimple()
+        {
+            return false;
+        }
+
+        public bool IsNullable()
+        {
+            return false;
+        }
+
+        public bool IsNull()
+        {
+            return false;
+        }
+
+        public bool IsBool()
+        {
+            return false;
+        }
+
+        public int GetBoolLength()
+        {
+            return 1;
+        }
+
+        public bool GetBool()
+        {
+            return default;
+        }
+
+        public bool GetBoolAt(int index)
+        {
+            if (index == 0)
+            {
+                return GetBool();
+            }
+            return default;
+        }
+
+        public bool[] GetBoolArray()
+        {
+            return default;
+        }
+
+        public bool IsByte()
+        {
+            return false;
+        }
+
+        public byte GetByte()
+        {
+            return default;
+        }
+
+        public bool IsUshort()
+        {
+            return false;
+        }
+
+        public ushort GetUshort()
+        {
+            return default;
+        }
+
+        public bool IsUint()
+        {
+            return false;
+        }
+
+        public uint GetUint()
+        {
+            return default;
+        }
+
+        public bool IsUlong()
+        {
+            return false;
+        }
+
+        public ulong GetUlong()
+        {
+            return default;
+        }
+
+        public bool IsSbyte()
+        {
+            return false;
+        }
+
+        public sbyte GetSbyte()
+        {
+            return default;
+        }
+
+        public bool IsShort()
+        {
+            return false;
+        }
+
+        public short GetShort()
+        {
+            return default;
+        }
+
+        public bool IsInt()
+        {
+            return false;
+        }
+
+        public int GetInt()
+        {
+            return default;
+        }
+
+        public bool IsLong()
+        {
+            return false;
+        }
+
+        public long GetLong()
+        {
+            return default;
+        }
+
+        public bool IsFloat()
+        {
+            return false;
+        }
+
+        public float GetFloat()
+        {
+            return default;
+        }
+
+        public bool IsDouble()
+        {
+            return false;
+        }
+
+        public double GetDouble()
+        {
+            return default;
+        }
+
+        public bool IsString()
+        {
+            return false;
+        }
+
+        public string GetString()
+        {
+            return default;
+        }
+
+        public bool IsDateTime()
+        {
+            return false;
+        }
+
+        public DateTime GetDateTime()
+        {
+            return default;
+        }
+
+        public byte[] GetRaw()
+        {
+            return default;
+        }
+
+        public bool IsList()
+        {
+            return false;
+        }
+
+        public int GetLength()
+        {
+            return 1;
+        }
+
+        public IPlcValue GetIndex(int index)
+        {
+            return default;
+        }
+
+        public IPlcValue[] GetList()
+        {
+            return default;
+        }
+
+        public bool IsStruct()
+        {
+            return false;
+        }
+
+        public string[] GetKeys()
+        {
+            return default;
+        }
+
+        public bool HasKey(string key)
+        {
+            return false;
+        }
+
+        public IPlcValue GetValue(string key)
+        {
+            return default;
+        }
+
+        public Dictionary<string, IPlcValue> GetStruct()
+        {
+            return default;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcWCHAR.cs b/sandbox/plc4net/spi/spi/model/values/PlcWCHAR.cs
new file mode 100644
index 0000000..5b34f8a
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcWCHAR.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcWCHAR : PlcSimpleValueAdapter
+    {
+        private char value;
+        
+        public PlcWCHAR(char value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcWORD.cs b/sandbox/plc4net/spi/spi/model/values/PlcWORD.cs
new file mode 100644
index 0000000..2af3b09
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcWORD.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcWORD : PlcBitString
+    {
+        private ushort value;
+        
+        public PlcWORD(ushort value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file
diff --git a/sandbox/plc4net/spi/spi/model/values/PlcWSTRING.cs b/sandbox/plc4net/spi/spi/model/values/PlcWSTRING.cs
new file mode 100644
index 0000000..e344e7e
--- /dev/null
+++ b/sandbox/plc4net/spi/spi/model/values/PlcWSTRING.cs
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+using org.apache.plc4net.api.value;
+
+namespace org.apache.plc4net.spi.model.values
+{
+    public class PlcWSTRING : PlcSimpleValueAdapter
+    {
+        private string value;
+        
+        public PlcWSTRING(string value)
+        {
+            this.value = value;
+        }
+    }
+}
\ No newline at end of file