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

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


The following commit(s) were added to refs/heads/develop by this push:
     new afd3939c6 chore(protocol/ads): Work on the new ADS driver - Switched 
the dataIo parsing of STRING and WSTRING from manual fields to simple fields 
with vstring - Fixed a problem in the go code generation causing problems 
accessing the "stringLength" serializer argument in dataIo types - Implemented 
the new state-machine for PLC4J ads driver
afd3939c6 is described below

commit afd3939c6eaf52670e69b3daaa4ecea87a5c3ab0
Author: Christofer Dutz <christofer.d...@c-ware.de>
AuthorDate: Mon Sep 26 10:37:30 2022 +0200

    chore(protocol/ads): Work on the new ADS driver
    - Switched the dataIo parsing of STRING and WSTRING from manual fields to 
simple fields with vstring
    - Fixed a problem in the go code generation causing problems accessing the 
"stringLength" serializer argument in dataIo types
    - Implemented the new state-machine for PLC4J ads driver
---
 .../language/go/GoLanguageTemplateHelper.java      |  12 +-
 .../mspec/model/definitions/DefaultArgument.java   |   5 +
 plc4go/protocols/ads/readwrite/model/DataItem.go   |  44 +-
 .../ads/readwrite/model/DefaultAmsPorts.go         | 552 +++++++++++++++++++++
 .../ads/readwrite/model/ReservedIndexGroups.go     |   8 +
 .../knxnetip/readwrite/model/KnxManufacturer.go    |  34 +-
 plc4go/protocols/s7/readwrite/model/DataItem.go    |   4 +-
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  | 444 ++++++++++++-----
 .../java/ads/readwrite/utils/StaticHelper.java     |  93 ----
 .../plc4x/protocol/ads/ManualAdsDriverTest.java    |  50 +-
 .../java/canopen/readwrite/utils/StaticHelper.java |   2 +-
 .../java/s7/readwrite/utils/StaticHelper.java      |   2 +-
 .../plc4x/java/spi/generation/ReadBuffer.java      |   4 +-
 .../java/spi/generation/ReadBufferByteBased.java   |  69 ++-
 .../plc4x/java/spi/generation/ReadBufferTest.java  |   2 +-
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |   2 +-
 .../org/apache/plc4x/test/manual/ManualTest.java   |  13 +-
 .../knxnetip/readwrite/model/KnxManufacturer.cs    |  23 +-
 .../ads/src/main/resources/protocols/ads/ads.mspec |  10 +-
 19 files changed, 1060 insertions(+), 313 deletions(-)

diff --git 
a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
 
b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
index 0afc466df..858ef2c34 100644
--- 
a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
+++ 
b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java
@@ -20,9 +20,11 @@ package org.apache.plc4x.language.go;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.math.NumberUtils;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions.DefaultArgument;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultBooleanTypeReference;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultFloatTypeReference;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultIntegerTypeReference;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultVstringTypeReference;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.DefaultStringLiteral;
 import 
org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
 import 
org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
@@ -467,7 +469,7 @@ public class GoLanguageTemplateHelper extends 
BaseFreemarkerLanguageTemplateHelp
                     .orElseThrow(() -> new RuntimeException("Encoding must be 
a literal"))
                     .asStringLiteral()
                     .orElseThrow(() -> new RuntimeException("Encoding must be 
a quoted string value")).getValue();
-                String lengthExpression = toExpression(field, null, 
vstringTypeReference.getLengthExpression(), null, null, true, false);
+                String lengthExpression = toExpression(field, null, 
vstringTypeReference.getLengthExpression(), null, Collections.singletonList(new 
DefaultArgument("stringLength", new 
DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.INT, 32))), 
true, false);
                 String length = 
Integer.toString(simpleTypeReference.getSizeInBits());
                 return "writeBuffer.WriteString(\"" + logicalName + "\", 
uint32(" + lengthExpression + "), \"" +
                     encoding + "\", " + fieldName + writerArgsString + ")";
@@ -847,7 +849,15 @@ public class GoLanguageTemplateHelper extends 
BaseFreemarkerLanguageTemplateHelp
             }
         }
 
+        // This is a special case for DataIo string types, which need to 
access the stringLength
         if ((serializerArguments != null) && serializerArguments.stream()
+            .anyMatch(argument -> 
argument.getName().equals(variableLiteralName)) && 
"stringLength".equals(variableLiteralName)) {
+            tracer = tracer.dive("serialization argument");
+            return tracer + variableLiteralName +
+                variableLiteral.getChild()
+                    .map(child -> "." + capitalize(toVariableExpression(field, 
typeReference, child, parserArguments, serializerArguments, false, 
suppressPointerAccess, true)))
+                    .orElse("");
+        } else if ((serializerArguments != null) && 
serializerArguments.stream()
             .anyMatch(argument -> 
argument.getName().equals(variableLiteralName))) {
             tracer = tracer.dive("serialization argument");
             return tracer + "m." + capitalize(variableLiteralName) +
diff --git 
a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java
 
b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java
index 93c57f81b..df1fad80e 100644
--- 
a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java
+++ 
b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java
@@ -37,6 +37,11 @@ public class DefaultArgument implements Argument {
         this.name = Objects.requireNonNull(name);
     }
 
+    public DefaultArgument(String name, TypeReference type) {
+        this.name = Objects.requireNonNull(name);
+        this.type = type;
+    }
+
     public String getName() {
         return name;
     }
diff --git a/plc4go/protocols/ads/readwrite/model/DataItem.go 
b/plc4go/protocols/ads/readwrite/model/DataItem.go
index ad0f76c64..4eb0283da 100644
--- a/plc4go/protocols/ads/readwrite/model/DataItem.go
+++ b/plc4go/protocols/ads/readwrite/model/DataItem.go
@@ -166,19 +166,29 @@ func DataItemParse(readBuffer utils.ReadBuffer, 
plcValueType PlcValueType, strin
                readBuffer.CloseContext("DataItem")
                return values.NewPlcSTRING(value), nil
        case plcValueType == PlcValueType_STRING: // STRING
-               // Manual Field (value)
-               value, _valueErr := ParseAmsString(readBuffer, stringLength, 
"UTF-8")
+               // Simple Field (value)
+               value, _valueErr := readBuffer.ReadString("value", 
uint32((stringLength)*(8)))
                if _valueErr != nil {
                        return nil, errors.Wrap(_valueErr, "Error parsing 
'value' field")
                }
+
+               // Reserved Field (Just skip the bytes)
+               if _, _err := readBuffer.ReadUint8("reserved", 8); _err != nil {
+                       return nil, errors.Wrap(_err, "Error parsing reserved 
field")
+               }
                readBuffer.CloseContext("DataItem")
                return values.NewPlcSTRING(value), nil
        case plcValueType == PlcValueType_WSTRING: // STRING
-               // Manual Field (value)
-               value, _valueErr := ParseAmsString(readBuffer, stringLength, 
"UTF-16")
+               // Simple Field (value)
+               value, _valueErr := readBuffer.ReadString("value", 
uint32(((stringLength)*(8))*(2)))
                if _valueErr != nil {
                        return nil, errors.Wrap(_valueErr, "Error parsing 
'value' field")
                }
+
+               // Reserved Field (Just skip the bytes)
+               if _, _err := readBuffer.ReadUint16("reserved", 16); _err != 
nil {
+                       return nil, errors.Wrap(_err, "Error parsing reserved 
field")
+               }
                readBuffer.CloseContext("DataItem")
                return values.NewPlcSTRING(value), nil
        case plcValueType == PlcValueType_TIME: // TIME
@@ -320,20 +330,28 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, 
value api.PlcValue, plcVal
                }
        case plcValueType == PlcValueType_WCHAR: // STRING
                // Simple Field (value)
-               if _err := writeBuffer.WriteString("value", uint32(16), 
"UTF-16", value.GetString()); _err != nil {
+               if _err := writeBuffer.WriteString("value", uint32(16), 
"UTF-16LE", value.GetString()); _err != nil {
                        return errors.Wrap(_err, "Error serializing 'value' 
field")
                }
        case plcValueType == PlcValueType_STRING: // STRING
-               // Manual Field (value)
-               _valueErr := SerializeAmsString(writeBuffer, value, 
m.StringLength, "UTF-8")
-               if _valueErr != nil {
-                       return errors.Wrap(_valueErr, "Error serializing 
'value' field")
+               // Simple Field (value)
+               if _err := writeBuffer.WriteString("value", 
uint32((stringLength)*(8)), "UTF-8", value.GetString()); _err != nil {
+                       return errors.Wrap(_err, "Error serializing 'value' 
field")
+               }
+
+               // Reserved Field (Just skip the bytes)
+               if _err := writeBuffer.WriteUint8("reserved", 8, uint8(0x00)); 
_err != nil {
+                       return errors.Wrap(_err, "Error serializing reserved 
field")
                }
        case plcValueType == PlcValueType_WSTRING: // STRING
-               // Manual Field (value)
-               _valueErr := SerializeAmsString(writeBuffer, value, 
m.StringLength, "UTF-16")
-               if _valueErr != nil {
-                       return errors.Wrap(_valueErr, "Error serializing 
'value' field")
+               // Simple Field (value)
+               if _err := writeBuffer.WriteString("value", 
uint32(((stringLength)*(8))*(2)), "UTF-16LE", value.GetString()); _err != nil {
+                       return errors.Wrap(_err, "Error serializing 'value' 
field")
+               }
+
+               // Reserved Field (Just skip the bytes)
+               if _err := writeBuffer.WriteUint16("reserved", 16, 
uint16(0x0000)); _err != nil {
+                       return errors.Wrap(_err, "Error serializing reserved 
field")
                }
        case plcValueType == PlcValueType_TIME: // TIME
                // Simple Field (value)
diff --git a/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go 
b/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go
new file mode 100644
index 000000000..2219b94a7
--- /dev/null
+++ b/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go
@@ -0,0 +1,552 @@
+/*
+ * 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
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package model
+
+import (
+       "github.com/apache/plc4x/plc4go/spi/utils"
+       "github.com/pkg/errors"
+)
+
+// Code generated by code-generation. DO NOT EDIT.
+
+// DefaultAmsPorts is an enum
+type DefaultAmsPorts uint16
+
+type IDefaultAmsPorts interface {
+       Serialize(writeBuffer utils.WriteBuffer) error
+}
+
+const (
+       DefaultAmsPorts_CAM_CONTROLLER      DefaultAmsPorts = 900
+       DefaultAmsPorts_RUNTIME_SYSTEM_01   DefaultAmsPorts = 851
+       DefaultAmsPorts_RUNTIME_SYSTEM_02   DefaultAmsPorts = 852
+       DefaultAmsPorts_RUNTIME_SYSTEM_03   DefaultAmsPorts = 853
+       DefaultAmsPorts_RUNTIME_SYSTEM_04   DefaultAmsPorts = 854
+       DefaultAmsPorts_RUNTIME_SYSTEM_05   DefaultAmsPorts = 855
+       DefaultAmsPorts_RUNTIME_SYSTEM_06   DefaultAmsPorts = 856
+       DefaultAmsPorts_RUNTIME_SYSTEM_07   DefaultAmsPorts = 857
+       DefaultAmsPorts_RUNTIME_SYSTEM_08   DefaultAmsPorts = 858
+       DefaultAmsPorts_RUNTIME_SYSTEM_09   DefaultAmsPorts = 859
+       DefaultAmsPorts_RUNTIME_SYSTEM_10   DefaultAmsPorts = 860
+       DefaultAmsPorts_RUNTIME_SYSTEM_11   DefaultAmsPorts = 861
+       DefaultAmsPorts_RUNTIME_SYSTEM_12   DefaultAmsPorts = 862
+       DefaultAmsPorts_RUNTIME_SYSTEM_13   DefaultAmsPorts = 863
+       DefaultAmsPorts_RUNTIME_SYSTEM_14   DefaultAmsPorts = 864
+       DefaultAmsPorts_RUNTIME_SYSTEM_15   DefaultAmsPorts = 865
+       DefaultAmsPorts_RUNTIME_SYSTEM_16   DefaultAmsPorts = 866
+       DefaultAmsPorts_RUNTIME_SYSTEM_17   DefaultAmsPorts = 867
+       DefaultAmsPorts_RUNTIME_SYSTEM_18   DefaultAmsPorts = 868
+       DefaultAmsPorts_RUNTIME_SYSTEM_19   DefaultAmsPorts = 869
+       DefaultAmsPorts_RUNTIME_SYSTEM_20   DefaultAmsPorts = 870
+       DefaultAmsPorts_RUNTIME_SYSTEM_21   DefaultAmsPorts = 871
+       DefaultAmsPorts_RUNTIME_SYSTEM_22   DefaultAmsPorts = 872
+       DefaultAmsPorts_RUNTIME_SYSTEM_23   DefaultAmsPorts = 873
+       DefaultAmsPorts_RUNTIME_SYSTEM_24   DefaultAmsPorts = 874
+       DefaultAmsPorts_RUNTIME_SYSTEM_25   DefaultAmsPorts = 875
+       DefaultAmsPorts_RUNTIME_SYSTEM_26   DefaultAmsPorts = 876
+       DefaultAmsPorts_RUNTIME_SYSTEM_27   DefaultAmsPorts = 877
+       DefaultAmsPorts_RUNTIME_SYSTEM_28   DefaultAmsPorts = 878
+       DefaultAmsPorts_RUNTIME_SYSTEM_29   DefaultAmsPorts = 879
+       DefaultAmsPorts_RUNTIME_SYSTEM_30   DefaultAmsPorts = 880
+       DefaultAmsPorts_RUNTIME_SYSTEM_31   DefaultAmsPorts = 881
+       DefaultAmsPorts_RUNTIME_SYSTEM_32   DefaultAmsPorts = 882
+       DefaultAmsPorts_RUNTIME_SYSTEM_33   DefaultAmsPorts = 883
+       DefaultAmsPorts_RUNTIME_SYSTEM_34   DefaultAmsPorts = 884
+       DefaultAmsPorts_RUNTIME_SYSTEM_35   DefaultAmsPorts = 885
+       DefaultAmsPorts_RUNTIME_SYSTEM_36   DefaultAmsPorts = 886
+       DefaultAmsPorts_RUNTIME_SYSTEM_37   DefaultAmsPorts = 887
+       DefaultAmsPorts_RUNTIME_SYSTEM_38   DefaultAmsPorts = 888
+       DefaultAmsPorts_RUNTIME_SYSTEM_39   DefaultAmsPorts = 889
+       DefaultAmsPorts_RUNTIME_SYSTEM_40   DefaultAmsPorts = 890
+       DefaultAmsPorts_RUNTIME_SYSTEM_41   DefaultAmsPorts = 891
+       DefaultAmsPorts_RUNTIME_SYSTEM_42   DefaultAmsPorts = 892
+       DefaultAmsPorts_RUNTIME_SYSTEM_43   DefaultAmsPorts = 893
+       DefaultAmsPorts_RUNTIME_SYSTEM_44   DefaultAmsPorts = 894
+       DefaultAmsPorts_RUNTIME_SYSTEM_45   DefaultAmsPorts = 895
+       DefaultAmsPorts_RUNTIME_SYSTEM_46   DefaultAmsPorts = 896
+       DefaultAmsPorts_RUNTIME_SYSTEM_47   DefaultAmsPorts = 897
+       DefaultAmsPorts_RUNTIME_SYSTEM_48   DefaultAmsPorts = 898
+       DefaultAmsPorts_RUNTIME_SYSTEM_49   DefaultAmsPorts = 899
+       DefaultAmsPorts_NC                  DefaultAmsPorts = 500
+       DefaultAmsPorts_RESERVED            DefaultAmsPorts = 400
+       DefaultAmsPorts_IO                  DefaultAmsPorts = 300
+       DefaultAmsPorts_REAL_TIME_CORE      DefaultAmsPorts = 200
+       DefaultAmsPorts_EVENT_SYSTEM_LOGGER DefaultAmsPorts = 100
+)
+
+var DefaultAmsPortsValues []DefaultAmsPorts
+
+func init() {
+       _ = errors.New
+       DefaultAmsPortsValues = []DefaultAmsPorts{
+               DefaultAmsPorts_CAM_CONTROLLER,
+               DefaultAmsPorts_RUNTIME_SYSTEM_01,
+               DefaultAmsPorts_RUNTIME_SYSTEM_02,
+               DefaultAmsPorts_RUNTIME_SYSTEM_03,
+               DefaultAmsPorts_RUNTIME_SYSTEM_04,
+               DefaultAmsPorts_RUNTIME_SYSTEM_05,
+               DefaultAmsPorts_RUNTIME_SYSTEM_06,
+               DefaultAmsPorts_RUNTIME_SYSTEM_07,
+               DefaultAmsPorts_RUNTIME_SYSTEM_08,
+               DefaultAmsPorts_RUNTIME_SYSTEM_09,
+               DefaultAmsPorts_RUNTIME_SYSTEM_10,
+               DefaultAmsPorts_RUNTIME_SYSTEM_11,
+               DefaultAmsPorts_RUNTIME_SYSTEM_12,
+               DefaultAmsPorts_RUNTIME_SYSTEM_13,
+               DefaultAmsPorts_RUNTIME_SYSTEM_14,
+               DefaultAmsPorts_RUNTIME_SYSTEM_15,
+               DefaultAmsPorts_RUNTIME_SYSTEM_16,
+               DefaultAmsPorts_RUNTIME_SYSTEM_17,
+               DefaultAmsPorts_RUNTIME_SYSTEM_18,
+               DefaultAmsPorts_RUNTIME_SYSTEM_19,
+               DefaultAmsPorts_RUNTIME_SYSTEM_20,
+               DefaultAmsPorts_RUNTIME_SYSTEM_21,
+               DefaultAmsPorts_RUNTIME_SYSTEM_22,
+               DefaultAmsPorts_RUNTIME_SYSTEM_23,
+               DefaultAmsPorts_RUNTIME_SYSTEM_24,
+               DefaultAmsPorts_RUNTIME_SYSTEM_25,
+               DefaultAmsPorts_RUNTIME_SYSTEM_26,
+               DefaultAmsPorts_RUNTIME_SYSTEM_27,
+               DefaultAmsPorts_RUNTIME_SYSTEM_28,
+               DefaultAmsPorts_RUNTIME_SYSTEM_29,
+               DefaultAmsPorts_RUNTIME_SYSTEM_30,
+               DefaultAmsPorts_RUNTIME_SYSTEM_31,
+               DefaultAmsPorts_RUNTIME_SYSTEM_32,
+               DefaultAmsPorts_RUNTIME_SYSTEM_33,
+               DefaultAmsPorts_RUNTIME_SYSTEM_34,
+               DefaultAmsPorts_RUNTIME_SYSTEM_35,
+               DefaultAmsPorts_RUNTIME_SYSTEM_36,
+               DefaultAmsPorts_RUNTIME_SYSTEM_37,
+               DefaultAmsPorts_RUNTIME_SYSTEM_38,
+               DefaultAmsPorts_RUNTIME_SYSTEM_39,
+               DefaultAmsPorts_RUNTIME_SYSTEM_40,
+               DefaultAmsPorts_RUNTIME_SYSTEM_41,
+               DefaultAmsPorts_RUNTIME_SYSTEM_42,
+               DefaultAmsPorts_RUNTIME_SYSTEM_43,
+               DefaultAmsPorts_RUNTIME_SYSTEM_44,
+               DefaultAmsPorts_RUNTIME_SYSTEM_45,
+               DefaultAmsPorts_RUNTIME_SYSTEM_46,
+               DefaultAmsPorts_RUNTIME_SYSTEM_47,
+               DefaultAmsPorts_RUNTIME_SYSTEM_48,
+               DefaultAmsPorts_RUNTIME_SYSTEM_49,
+               DefaultAmsPorts_NC,
+               DefaultAmsPorts_RESERVED,
+               DefaultAmsPorts_IO,
+               DefaultAmsPorts_REAL_TIME_CORE,
+               DefaultAmsPorts_EVENT_SYSTEM_LOGGER,
+       }
+}
+
+func DefaultAmsPortsByValue(value uint16) (enum DefaultAmsPorts, ok bool) {
+       switch value {
+       case 100:
+               return DefaultAmsPorts_EVENT_SYSTEM_LOGGER, true
+       case 200:
+               return DefaultAmsPorts_REAL_TIME_CORE, true
+       case 300:
+               return DefaultAmsPorts_IO, true
+       case 400:
+               return DefaultAmsPorts_RESERVED, true
+       case 500:
+               return DefaultAmsPorts_NC, true
+       case 851:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_01, true
+       case 852:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_02, true
+       case 853:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_03, true
+       case 854:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_04, true
+       case 855:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_05, true
+       case 856:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_06, true
+       case 857:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_07, true
+       case 858:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_08, true
+       case 859:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_09, true
+       case 860:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_10, true
+       case 861:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_11, true
+       case 862:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_12, true
+       case 863:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_13, true
+       case 864:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_14, true
+       case 865:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_15, true
+       case 866:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_16, true
+       case 867:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_17, true
+       case 868:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_18, true
+       case 869:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_19, true
+       case 870:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_20, true
+       case 871:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_21, true
+       case 872:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_22, true
+       case 873:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_23, true
+       case 874:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_24, true
+       case 875:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_25, true
+       case 876:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_26, true
+       case 877:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_27, true
+       case 878:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_28, true
+       case 879:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_29, true
+       case 880:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_30, true
+       case 881:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_31, true
+       case 882:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_32, true
+       case 883:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_33, true
+       case 884:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_34, true
+       case 885:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_35, true
+       case 886:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_36, true
+       case 887:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_37, true
+       case 888:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_38, true
+       case 889:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_39, true
+       case 890:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_40, true
+       case 891:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_41, true
+       case 892:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_42, true
+       case 893:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_43, true
+       case 894:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_44, true
+       case 895:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_45, true
+       case 896:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_46, true
+       case 897:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_47, true
+       case 898:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_48, true
+       case 899:
+               return DefaultAmsPorts_RUNTIME_SYSTEM_49, true
+       case 900:
+               return DefaultAmsPorts_CAM_CONTROLLER, true
+       }
+       return 0, false
+}
+
+func DefaultAmsPortsByName(value string) (enum DefaultAmsPorts, ok bool) {
+       switch value {
+       case "EVENT_SYSTEM_LOGGER":
+               return DefaultAmsPorts_EVENT_SYSTEM_LOGGER, true
+       case "REAL_TIME_CORE":
+               return DefaultAmsPorts_REAL_TIME_CORE, true
+       case "IO":
+               return DefaultAmsPorts_IO, true
+       case "RESERVED":
+               return DefaultAmsPorts_RESERVED, true
+       case "NC":
+               return DefaultAmsPorts_NC, true
+       case "RUNTIME_SYSTEM_01":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_01, true
+       case "RUNTIME_SYSTEM_02":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_02, true
+       case "RUNTIME_SYSTEM_03":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_03, true
+       case "RUNTIME_SYSTEM_04":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_04, true
+       case "RUNTIME_SYSTEM_05":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_05, true
+       case "RUNTIME_SYSTEM_06":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_06, true
+       case "RUNTIME_SYSTEM_07":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_07, true
+       case "RUNTIME_SYSTEM_08":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_08, true
+       case "RUNTIME_SYSTEM_09":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_09, true
+       case "RUNTIME_SYSTEM_10":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_10, true
+       case "RUNTIME_SYSTEM_11":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_11, true
+       case "RUNTIME_SYSTEM_12":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_12, true
+       case "RUNTIME_SYSTEM_13":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_13, true
+       case "RUNTIME_SYSTEM_14":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_14, true
+       case "RUNTIME_SYSTEM_15":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_15, true
+       case "RUNTIME_SYSTEM_16":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_16, true
+       case "RUNTIME_SYSTEM_17":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_17, true
+       case "RUNTIME_SYSTEM_18":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_18, true
+       case "RUNTIME_SYSTEM_19":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_19, true
+       case "RUNTIME_SYSTEM_20":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_20, true
+       case "RUNTIME_SYSTEM_21":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_21, true
+       case "RUNTIME_SYSTEM_22":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_22, true
+       case "RUNTIME_SYSTEM_23":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_23, true
+       case "RUNTIME_SYSTEM_24":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_24, true
+       case "RUNTIME_SYSTEM_25":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_25, true
+       case "RUNTIME_SYSTEM_26":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_26, true
+       case "RUNTIME_SYSTEM_27":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_27, true
+       case "RUNTIME_SYSTEM_28":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_28, true
+       case "RUNTIME_SYSTEM_29":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_29, true
+       case "RUNTIME_SYSTEM_30":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_30, true
+       case "RUNTIME_SYSTEM_31":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_31, true
+       case "RUNTIME_SYSTEM_32":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_32, true
+       case "RUNTIME_SYSTEM_33":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_33, true
+       case "RUNTIME_SYSTEM_34":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_34, true
+       case "RUNTIME_SYSTEM_35":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_35, true
+       case "RUNTIME_SYSTEM_36":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_36, true
+       case "RUNTIME_SYSTEM_37":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_37, true
+       case "RUNTIME_SYSTEM_38":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_38, true
+       case "RUNTIME_SYSTEM_39":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_39, true
+       case "RUNTIME_SYSTEM_40":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_40, true
+       case "RUNTIME_SYSTEM_41":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_41, true
+       case "RUNTIME_SYSTEM_42":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_42, true
+       case "RUNTIME_SYSTEM_43":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_43, true
+       case "RUNTIME_SYSTEM_44":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_44, true
+       case "RUNTIME_SYSTEM_45":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_45, true
+       case "RUNTIME_SYSTEM_46":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_46, true
+       case "RUNTIME_SYSTEM_47":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_47, true
+       case "RUNTIME_SYSTEM_48":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_48, true
+       case "RUNTIME_SYSTEM_49":
+               return DefaultAmsPorts_RUNTIME_SYSTEM_49, true
+       case "CAM_CONTROLLER":
+               return DefaultAmsPorts_CAM_CONTROLLER, true
+       }
+       return 0, false
+}
+
+func DefaultAmsPortsKnows(value uint16) bool {
+       for _, typeValue := range DefaultAmsPortsValues {
+               if uint16(typeValue) == value {
+                       return true
+               }
+       }
+       return false
+}
+
+func CastDefaultAmsPorts(structType interface{}) DefaultAmsPorts {
+       castFunc := func(typ interface{}) DefaultAmsPorts {
+               if sDefaultAmsPorts, ok := typ.(DefaultAmsPorts); ok {
+                       return sDefaultAmsPorts
+               }
+               return 0
+       }
+       return castFunc(structType)
+}
+
+func (m DefaultAmsPorts) GetLengthInBits() uint16 {
+       return 16
+}
+
+func (m DefaultAmsPorts) GetLengthInBytes() uint16 {
+       return m.GetLengthInBits() / 8
+}
+
+func DefaultAmsPortsParse(readBuffer utils.ReadBuffer) (DefaultAmsPorts, 
error) {
+       val, err := readBuffer.ReadUint16("DefaultAmsPorts", 16)
+       if err != nil {
+               return 0, errors.Wrap(err, "error reading DefaultAmsPorts")
+       }
+       if enum, ok := DefaultAmsPortsByValue(val); !ok {
+               Plc4xModelLog.Debug().Msgf("no value %x found for RequestType", 
val)
+               return DefaultAmsPorts(val), nil
+       } else {
+               return enum, nil
+       }
+}
+
+func (e DefaultAmsPorts) Serialize(writeBuffer utils.WriteBuffer) error {
+       return writeBuffer.WriteUint16("DefaultAmsPorts", 16, uint16(e), 
utils.WithAdditionalStringRepresentation(e.PLC4XEnumName()))
+}
+
+// PLC4XEnumName returns the name that is used in code to identify this enum
+func (e DefaultAmsPorts) PLC4XEnumName() string {
+       switch e {
+       case DefaultAmsPorts_EVENT_SYSTEM_LOGGER:
+               return "EVENT_SYSTEM_LOGGER"
+       case DefaultAmsPorts_REAL_TIME_CORE:
+               return "REAL_TIME_CORE"
+       case DefaultAmsPorts_IO:
+               return "IO"
+       case DefaultAmsPorts_RESERVED:
+               return "RESERVED"
+       case DefaultAmsPorts_NC:
+               return "NC"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_01:
+               return "RUNTIME_SYSTEM_01"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_02:
+               return "RUNTIME_SYSTEM_02"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_03:
+               return "RUNTIME_SYSTEM_03"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_04:
+               return "RUNTIME_SYSTEM_04"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_05:
+               return "RUNTIME_SYSTEM_05"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_06:
+               return "RUNTIME_SYSTEM_06"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_07:
+               return "RUNTIME_SYSTEM_07"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_08:
+               return "RUNTIME_SYSTEM_08"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_09:
+               return "RUNTIME_SYSTEM_09"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_10:
+               return "RUNTIME_SYSTEM_10"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_11:
+               return "RUNTIME_SYSTEM_11"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_12:
+               return "RUNTIME_SYSTEM_12"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_13:
+               return "RUNTIME_SYSTEM_13"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_14:
+               return "RUNTIME_SYSTEM_14"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_15:
+               return "RUNTIME_SYSTEM_15"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_16:
+               return "RUNTIME_SYSTEM_16"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_17:
+               return "RUNTIME_SYSTEM_17"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_18:
+               return "RUNTIME_SYSTEM_18"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_19:
+               return "RUNTIME_SYSTEM_19"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_20:
+               return "RUNTIME_SYSTEM_20"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_21:
+               return "RUNTIME_SYSTEM_21"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_22:
+               return "RUNTIME_SYSTEM_22"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_23:
+               return "RUNTIME_SYSTEM_23"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_24:
+               return "RUNTIME_SYSTEM_24"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_25:
+               return "RUNTIME_SYSTEM_25"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_26:
+               return "RUNTIME_SYSTEM_26"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_27:
+               return "RUNTIME_SYSTEM_27"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_28:
+               return "RUNTIME_SYSTEM_28"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_29:
+               return "RUNTIME_SYSTEM_29"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_30:
+               return "RUNTIME_SYSTEM_30"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_31:
+               return "RUNTIME_SYSTEM_31"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_32:
+               return "RUNTIME_SYSTEM_32"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_33:
+               return "RUNTIME_SYSTEM_33"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_34:
+               return "RUNTIME_SYSTEM_34"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_35:
+               return "RUNTIME_SYSTEM_35"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_36:
+               return "RUNTIME_SYSTEM_36"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_37:
+               return "RUNTIME_SYSTEM_37"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_38:
+               return "RUNTIME_SYSTEM_38"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_39:
+               return "RUNTIME_SYSTEM_39"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_40:
+               return "RUNTIME_SYSTEM_40"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_41:
+               return "RUNTIME_SYSTEM_41"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_42:
+               return "RUNTIME_SYSTEM_42"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_43:
+               return "RUNTIME_SYSTEM_43"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_44:
+               return "RUNTIME_SYSTEM_44"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_45:
+               return "RUNTIME_SYSTEM_45"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_46:
+               return "RUNTIME_SYSTEM_46"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_47:
+               return "RUNTIME_SYSTEM_47"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_48:
+               return "RUNTIME_SYSTEM_48"
+       case DefaultAmsPorts_RUNTIME_SYSTEM_49:
+               return "RUNTIME_SYSTEM_49"
+       case DefaultAmsPorts_CAM_CONTROLLER:
+               return "CAM_CONTROLLER"
+       }
+       return ""
+}
+
+func (e DefaultAmsPorts) String() string {
+       return e.PLC4XEnumName()
+}
diff --git a/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go 
b/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go
index 4ea3e9c11..11990ece9 100644
--- a/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go
+++ b/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go
@@ -50,6 +50,7 @@ const (
        ReservedIndexGroups_ADSIGRP_DATA_TYPE_TABLE_UPLOAD               
ReservedIndexGroups = 0x0000F00E
        ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES           
ReservedIndexGroups = 0x0000F00F
        ReservedIndexGroups_ADSIGRP_SYMNOTE                              
ReservedIndexGroups = 0x0000F010
+       ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX                      
ReservedIndexGroups = 0x0000F011
        ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB                         
ReservedIndexGroups = 0x0000F020
        ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX                         
ReservedIndexGroups = 0x0000F021
        ReservedIndexGroups_ADSIGRP_IOIMAGE_RISIZE                       
ReservedIndexGroups = 0x0000F025
@@ -92,6 +93,7 @@ func init() {
                ReservedIndexGroups_ADSIGRP_DATA_TYPE_TABLE_UPLOAD,
                ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES,
                ReservedIndexGroups_ADSIGRP_SYMNOTE,
+               ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX,
                ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB,
                ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX,
                ReservedIndexGroups_ADSIGRP_IOIMAGE_RISIZE,
@@ -152,6 +154,8 @@ func ReservedIndexGroupsByValue(value uint32) (enum 
ReservedIndexGroups, ok bool
                return ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES, 
true
        case 0x0000F010:
                return ReservedIndexGroups_ADSIGRP_SYMNOTE, true
+       case 0x0000F011:
+               return ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX, true
        case 0x0000F020:
                return ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB, true
        case 0x0000F021:
@@ -228,6 +232,8 @@ func ReservedIndexGroupsByName(value string) (enum 
ReservedIndexGroups, ok bool)
                return ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES, 
true
        case "ADSIGRP_SYMNOTE":
                return ReservedIndexGroups_ADSIGRP_SYMNOTE, true
+       case "ADSIGRP_DT_INFOBYNAMEEX":
+               return ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX, true
        case "ADSIGRP_IOIMAGE_RWIB":
                return ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB, true
        case "ADSIGRP_IOIMAGE_RWIX":
@@ -349,6 +355,8 @@ func (e ReservedIndexGroups) PLC4XEnumName() string {
                return "ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES"
        case ReservedIndexGroups_ADSIGRP_SYMNOTE:
                return "ADSIGRP_SYMNOTE"
+       case ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX:
+               return "ADSIGRP_DT_INFOBYNAMEEX"
        case ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB:
                return "ADSIGRP_IOIMAGE_RWIB"
        case ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX:
diff --git a/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go 
b/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go
index 9050d1663..4c70cdae6 100644
--- a/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go
+++ b/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go
@@ -635,8 +635,9 @@ const (
        KnxManufacturer_M_GUANGDONG_KANWAY                                   
KnxManufacturer = 596
        KnxManufacturer_M_PHOENIX_CONTACT_2                                  
KnxManufacturer = 597
        KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH                           
KnxManufacturer = 598
-       KnxManufacturer_M_ABB___RESERVED                                     
KnxManufacturer = 599
-       KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED                    
KnxManufacturer = 600
+       KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD                
KnxManufacturer = 599
+       KnxManufacturer_M_ABB___RESERVED                                     
KnxManufacturer = 600
+       KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED                    
KnxManufacturer = 601
 )
 
 var KnxManufacturerValues []KnxManufacturer
@@ -1243,6 +1244,7 @@ func init() {
                KnxManufacturer_M_GUANGDONG_KANWAY,
                KnxManufacturer_M_PHOENIX_CONTACT_2,
                KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH,
+               KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD,
                KnxManufacturer_M_ABB___RESERVED,
                KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED,
        }
@@ -3472,7 +3474,7 @@ func (e KnxManufacturer) Number() uint16 {
                }
        case 599:
                { /* '599' */
-                       return 43954
+                       return 657
                }
        case 6:
                { /* '6' */
@@ -3484,6 +3486,10 @@ func (e KnxManufacturer) Number() uint16 {
                }
        case 600:
                { /* '600' */
+                       return 43954
+               }
+       case 601:
+               { /* '601' */
                        return 43959
                }
        case 61:
@@ -5894,7 +5900,7 @@ func (e KnxManufacturer) Name() string {
                }
        case 599:
                { /* '599' */
-                       return "ABB - reserved"
+                       return "Zhongshan Taiyang IMP&EXP. CO LTD"
                }
        case 6:
                { /* '6' */
@@ -5906,6 +5912,10 @@ func (e KnxManufacturer) Name() string {
                }
        case 600:
                { /* '600' */
+                       return "ABB - reserved"
+               }
+       case 601:
+               { /* '601' */
                        return "Busch-Jaeger Elektro - reserved"
                }
        case 61:
@@ -7204,12 +7214,14 @@ func KnxManufacturerByValue(value uint16) (enum 
KnxManufacturer, ok bool) {
        case 598:
                return KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH, true
        case 599:
-               return KnxManufacturer_M_ABB___RESERVED, true
+               return KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD, 
true
        case 6:
                return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO, true
        case 60:
                return KnxManufacturer_M_TECHEM, true
        case 600:
+               return KnxManufacturer_M_ABB___RESERVED, true
+       case 601:
                return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED, true
        case 61:
                return KnxManufacturer_M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS, true
@@ -8411,12 +8423,14 @@ func KnxManufacturerByName(value string) (enum 
KnxManufacturer, ok bool) {
                return KnxManufacturer_M_PHOENIX_CONTACT_2, true
        case "M_RAMIREZ_ENGINEERING_GMBH":
                return KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH, true
-       case "M_ABB___RESERVED":
-               return KnxManufacturer_M_ABB___RESERVED, true
+       case "M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD":
+               return KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD, 
true
        case "M_BUSCH_JAEGER_ELEKTRO":
                return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO, true
        case "M_TECHEM":
                return KnxManufacturer_M_TECHEM, true
+       case "M_ABB___RESERVED":
+               return KnxManufacturer_M_ABB___RESERVED, true
        case "M_BUSCH_JAEGER_ELEKTRO___RESERVED":
                return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED, true
        case "M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS":
@@ -9664,12 +9678,14 @@ func (e KnxManufacturer) PLC4XEnumName() string {
                return "M_PHOENIX_CONTACT_2"
        case KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH:
                return "M_RAMIREZ_ENGINEERING_GMBH"
-       case KnxManufacturer_M_ABB___RESERVED:
-               return "M_ABB___RESERVED"
+       case KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD:
+               return "M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD"
        case KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO:
                return "M_BUSCH_JAEGER_ELEKTRO"
        case KnxManufacturer_M_TECHEM:
                return "M_TECHEM"
+       case KnxManufacturer_M_ABB___RESERVED:
+               return "M_ABB___RESERVED"
        case KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED:
                return "M_BUSCH_JAEGER_ELEKTRO___RESERVED"
        case KnxManufacturer_M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS:
diff --git a/plc4go/protocols/s7/readwrite/model/DataItem.go 
b/plc4go/protocols/s7/readwrite/model/DataItem.go
index 42010eed2..d0ad80537 100644
--- a/plc4go/protocols/s7/readwrite/model/DataItem.go
+++ b/plc4go/protocols/s7/readwrite/model/DataItem.go
@@ -410,13 +410,13 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, 
value api.PlcValue, dataPr
                }
        case dataProtocolId == "IEC61131_STRING": // STRING
                // Manual Field (value)
-               _valueErr := SerializeS7String(writeBuffer, value, 
m.StringLength, "UTF-8")
+               _valueErr := SerializeS7String(writeBuffer, value, 
stringLength, "UTF-8")
                if _valueErr != nil {
                        return errors.Wrap(_valueErr, "Error serializing 
'value' field")
                }
        case dataProtocolId == "IEC61131_WSTRING": // STRING
                // Manual Field (value)
-               _valueErr := SerializeS7String(writeBuffer, value, 
m.StringLength, "UTF-16")
+               _valueErr := SerializeS7String(writeBuffer, value, 
stringLength, "UTF-16")
                if _valueErr != nil {
                        return errors.Wrap(_valueErr, "Error serializing 
'value' field")
                }
diff --git 
a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
 
b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
index 377334bbe..1f4fa085f 100644
--- 
a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
+++ 
b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
@@ -28,10 +28,12 @@ import org.apache.plc4x.java.ads.readwrite.DataItem;
 import 
org.apache.plc4x.java.api.authentication.PlcUsernamePasswordAuthentication;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcException;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.types.PlcSubscriptionType;
@@ -51,12 +53,14 @@ import org.slf4j.LoggerFactory;
 
 import java.math.BigInteger;
 import java.net.*;
+import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.time.Instant;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -67,22 +71,28 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
 
     private AdsConfiguration configuration;
 
+    private String adsVersion;
+    private String deviceName;
+
     private final AtomicLong invokeIdGenerator = new AtomicLong(1);
     private final RequestTransactionManager tm;
 
     private final Map<DefaultPlcConsumerRegistration, 
Consumer<PlcSubscriptionEvent>> consumers = new ConcurrentHashMap<>();
 
-    //    private final ConcurrentHashMap<SymbolicAdsField, DirectAdsField> 
symbolicFieldMapping;
     private final ConcurrentHashMap<SymbolicAdsField, CompletableFuture<Void>> 
pendingResolutionRequests;
 
+    private int symbolVersion;
+    private long onlineVersion;
     private final Map<String, AdsSymbolTableEntry> symbolTable;
     private final Map<String, AdsDataTypeTableEntry> dataTypeTable;
+    private final ReentrantLock invalidationLock;
 
     public AdsProtocolLogic() {
 //        symbolicFieldMapping = new ConcurrentHashMap<>();
         pendingResolutionRequests = new ConcurrentHashMap<>();
         symbolTable = new HashMap<>();
         dataTypeTable = new HashMap<>();
+        invalidationLock = new ReentrantLock();
 
         // Initialize Transaction Manager.
         // Until the number of concurrent requests is successfully negotiated 
we set it to a
@@ -125,19 +135,104 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         // If the configuration asks us to load the symbol and data type 
tables, do so,
         // otherwise just mark the connection as completed instantly.
         setupAmsRouteFuture.whenComplete((unused, throwable) -> {
-            if (configuration.isLoadSymbolAndDataTypeTables()) {
-                LOGGER.debug("Fetching sizes of symbol and datatype table 
sizes.");
-                CompletableFuture<Void> readSymbolTableFuture = 
readSymbolTableAndDatatypeTable(context);
-                readSymbolTableFuture.whenComplete((unused2, throwable2) -> {
-                    if (throwable2 != null) {
-                        LOGGER.error("Error fetching symbol and datatype table 
sizes");
-                    } else {
-                        context.fireConnected();
-                    }
-                });
-            } else {
-                context.fireConnected();
+            if (!configuration.isLoadSymbolAndDataTypeTables()) {
+                future.completeExceptionally(new PlcConnectionException(
+                    "Lazy loading is generally planned, but not implemented 
yet. " +
+                        "If you are in need for this feature, please reach out 
to the community."));
             }
+            //if (configuration.isLoadSymbolAndDataTypeTables()) {
+                // Execute a ReadDeviceInfo command
+                AmsPacket readDeviceInfoRequest = new AdsReadDeviceInfoRequest(
+                    configuration.getTargetAmsNetId(), 
DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(),
+                    configuration.getSourceAmsNetId(), 800, 0, getInvokeId());
+                RequestTransactionManager.RequestTransaction readDeviceInfoTx 
= tm.startRequest();
+                readDeviceInfoTx.submit(() -> context.sendRequest(new 
AmsTCPPacket(readDeviceInfoRequest))
+                    .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
+                    .onTimeout(future::completeExceptionally)
+                    .onError((p, e) -> future.completeExceptionally(e))
+                    .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readDeviceInfoRequest.getInvokeId())
+                    .unwrap(response -> (AdsReadDeviceInfoResponse) 
response.getUserdata())
+                    .handle(readDeviceInfoResponse -> {
+                        readDeviceInfoTx.endRequest();
+                        if (readDeviceInfoResponse.getResult() != 
ReturnCode.OK) {
+                            // TODO: Handle this
+                            future.completeExceptionally(new 
PlcException("Result is " + readDeviceInfoResponse.getResult()));
+                            return;
+                        }
+
+                        // Get the twin-cat version and PLC name.
+                        adsVersion = String.format("%d.%d.%d", 
readDeviceInfoResponse.getMajorVersion(),
+                            readDeviceInfoResponse.getMinorVersion(), 
readDeviceInfoResponse.getVersion());
+                        deviceName = new 
String(readDeviceInfoResponse.getDevice()).trim();
+
+                        // Read the online version number (Address; GroupID: 
0xF004 (read symbol by name),Offset: 0, Read length: 4, ... Payload: 
"TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt")
+                        AmsPacket readOnlineVersionNumberRequest = new 
AdsReadWriteRequest(
+                            configuration.getTargetAmsNetId(), 
DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(),
+                            configuration.getSourceAmsNetId(), 800, 0, 
getInvokeId(),
+                            
ReservedIndexGroups.ADSIGRP_SYM_VALBYNAME.getValue(), 0, 4, null,
+                            
"TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt".getBytes(StandardCharsets.UTF_8));
+                        RequestTransactionManager.RequestTransaction 
readOnlineVersionNumberTx = tm.startRequest();
+                        readOnlineVersionNumberTx.submit(() -> 
context.sendRequest(new AmsTCPPacket(readOnlineVersionNumberRequest))
+                            .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
+                            .onTimeout(future::completeExceptionally)
+                            .onError((p, e) -> future.completeExceptionally(e))
+                            .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readOnlineVersionNumberRequest.getInvokeId())
+                            .unwrap(response -> (AdsReadWriteResponse) 
response.getUserdata())
+                            .handle(readOnlineVersionNumberResponse -> {
+                                readOnlineVersionNumberTx.endRequest();
+                                if 
(readOnlineVersionNumberResponse.getResult() != ReturnCode.OK) {
+                                    // TODO: Handle this
+                                    future.completeExceptionally(new 
PlcException("Result is " + readOnlineVersionNumberResponse.getResult()));
+                                    return;
+                                }
+                                try {
+                                    ReadBuffer rb = new 
ReadBufferByteBased(readOnlineVersionNumberResponse.getData());
+                                    onlineVersion = rb.readUnsignedLong(32);
+
+                                    // Read the offline version number 
(Address: GroupID: 0xF008, Offset: 0, Read length: 1)
+                                    AmsPacket readSymbolVersionNumberRequest = 
new AdsReadRequest(
+                                        configuration.getTargetAmsNetId(), 
DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(),
+                                        configuration.getSourceAmsNetId(), 
800, 0, getInvokeId(),
+                                        
ReservedIndexGroups.ADSIGRP_SYM_VERSION.getValue(), 0, 1);
+                                    
RequestTransactionManager.RequestTransaction readSymbolVersionNumberTx = 
tm.startRequest();
+                                    readSymbolVersionNumberTx.submit(() -> 
context.sendRequest(new AmsTCPPacket(readSymbolVersionNumberRequest))
+                                        .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
+                                        
.onTimeout(future::completeExceptionally)
+                                        .onError((p, e) -> 
future.completeExceptionally(e))
+                                        .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readSymbolVersionNumberRequest.getInvokeId())
+                                        .unwrap(response -> (AdsReadResponse) 
response.getUserdata())
+                                        
.handle(readSymbolVersionNumberResponse -> {
+                                            
readSymbolVersionNumberTx.endRequest();
+                                            if 
(readSymbolVersionNumberResponse.getResult() != ReturnCode.OK) {
+                                                // TODO: Handle this
+                                                
future.completeExceptionally(new PlcException("Result is " + 
readSymbolVersionNumberResponse.getResult()));
+                                                return;
+                                            }
+                                            try {
+                                                ReadBuffer rb2 = new 
ReadBufferByteBased(readSymbolVersionNumberResponse.getData());
+                                                symbolVersion = 
rb2.readUnsignedInt(8);
+
+                                                LOGGER.debug("Fetching sizes 
of symbol and datatype table sizes.");
+                                                CompletableFuture<Void> 
readSymbolTableFuture = readSymbolTableAndDatatypeTable(context);
+                                                
readSymbolTableFuture.whenComplete((unused2, throwable2) -> {
+                                                    if (throwable2 != null) {
+                                                        LOGGER.error("Error 
fetching symbol and datatype table sizes");
+                                                    } else {
+                                                        
context.fireConnected();
+                                                    }
+                                                });
+                                            } catch (ParseException e) {
+                                                
future.completeExceptionally(new PlcConnectionException("Error reading the 
symbol version of data type and symbol data.", e));
+                                            }
+                                        }));
+                                } catch (ParseException e) {
+                                    future.completeExceptionally(new 
PlcConnectionException("Error reading the online version of data type and 
symbol data.", e));
+                                }
+                            }));
+                    }));
+            /*} else {
+                context.fireConnected();
+            }*/
         });
     }
 
@@ -217,88 +312,146 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     protected CompletableFuture<Void> 
readSymbolTableAndDatatypeTable(ConversationContext<AmsTCPPacket> context) {
         final CompletableFuture<Void> future = new CompletableFuture<>();
 
-        // Initialize the request.
-        AmsPacket amsPacket = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
+        // Read the data-type and symbol table sizes
+        AmsPacket readDataAndSymbolTableSizesRequest = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
             configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(), 0, getInvokeId(),
             ReservedIndexGroups.ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES.getValue(), 
0x00000000, 24);
-        AmsTCPPacket amsTCPPacket = new AmsTCPPacket(amsPacket);
-        // Start a new request-transaction (Is ended in the response-handler)
-        RequestTransactionManager.RequestTransaction transaction = 
tm.startRequest();
-        transaction.submit(() -> context.sendRequest(amsTCPPacket)
+        RequestTransactionManager.RequestTransaction 
readDataAndSymbolTableSizesTx = tm.startRequest();
+        readDataAndSymbolTableSizesTx.submit(() -> context.sendRequest(new 
AmsTCPPacket(readDataAndSymbolTableSizesRequest))
             .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
             .onTimeout(future::completeExceptionally)
             .onError((p, e) -> future.completeExceptionally(e))
-            .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId())
+            .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readDataAndSymbolTableSizesRequest.getInvokeId())
             .unwrap(response -> (AdsReadResponse) response.getUserdata())
-            .handle(responseAdsData -> {
-                transaction.endRequest();
-                if (responseAdsData.getResult() == ReturnCode.OK) {
-                    ReadBuffer readBuffer = new 
ReadBufferByteBased(responseAdsData.getData());
-                    try {
-                        AdsTableSizes adsTableSizes = 
AdsTableSizes.staticParse(readBuffer);
-                        LOGGER.debug("PLC contains {} symbols and {} 
data-types", adsTableSizes.getSymbolCount(), adsTableSizes.getDataTypeCount());
-
-                        // Now we load the datatype definitions.
-                        AmsPacket amsReadTablePacket = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
-                            configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(), 0, getInvokeId(),
-                            
ReservedIndexGroups.ADSIGRP_DATA_TYPE_TABLE_UPLOAD.getValue(), 0x00000000, 
adsTableSizes.getDataTypeLength());
-                        RequestTransactionManager.RequestTransaction 
transaction2 = tm.startRequest();
-                        AmsTCPPacket amsReadTableTCPPacket = new 
AmsTCPPacket(amsReadTablePacket);
-                        transaction2.submit(() -> 
context.sendRequest(amsReadTableTCPPacket)
-                            .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
-                            .onTimeout(future::completeExceptionally)
-                            .onError((p, e) -> future.completeExceptionally(e))
-                            .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
amsReadTablePacket.getInvokeId())
-                            .unwrap(response -> (AdsReadResponse) 
response.getUserdata())
-                            .handle(responseAdsReadTableData -> {
-                                transaction2.endRequest();
-                                if (responseAdsData.getResult() == 
ReturnCode.OK) {
-                                    // Parse the result.
-                                    ReadBuffer rb = new 
ReadBufferByteBased(responseAdsReadTableData.getData());
-                                    for (int i = 0; i < 
adsTableSizes.getDataTypeCount(); i++) {
+            .handle(readDataAndSymbolTableSizesResponse -> {
+                readDataAndSymbolTableSizesTx.endRequest();
+                if (readDataAndSymbolTableSizesResponse.getResult() != 
ReturnCode.OK) {
+                    // TODO: Handle this
+                    future.completeExceptionally(new PlcException("Reading 
data type and symbol table sizes failed: " + 
readDataAndSymbolTableSizesResponse.getResult()));
+                    return;
+                }
+                try {
+                    ReadBuffer readBuffer = new 
ReadBufferByteBased(readDataAndSymbolTableSizesResponse.getData());
+                    AdsTableSizes adsTableSizes = 
AdsTableSizes.staticParse(readBuffer);
+                    LOGGER.debug("PLC contains {} symbols and {} data-types", 
adsTableSizes.getSymbolCount(), adsTableSizes.getDataTypeCount());
+
+                    // Now we load the datatype definitions.
+                    AmsPacket readDataTypeTableRequest = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
+                        configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(), 0, getInvokeId(),
+                        
ReservedIndexGroups.ADSIGRP_DATA_TYPE_TABLE_UPLOAD.getValue(), 0x00000000, 
adsTableSizes.getDataTypeLength());
+                    RequestTransactionManager.RequestTransaction 
readDataTypeTableTx = tm.startRequest();
+                    AmsTCPPacket amsReadTableTCPPacket = new 
AmsTCPPacket(readDataTypeTableRequest);
+                    readDataTypeTableTx.submit(() -> 
context.sendRequest(amsReadTableTCPPacket)
+                        .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
+                        .onTimeout(future::completeExceptionally)
+                        .onError((p, e) -> future.completeExceptionally(e))
+                        .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readDataTypeTableRequest.getInvokeId())
+                        .unwrap(response -> (AdsReadResponse) 
response.getUserdata())
+                        .handle(readDataTypeTableResponse -> {
+                            readDataTypeTableTx.endRequest();
+                            if (readDataTypeTableResponse.getResult() != 
ReturnCode.OK) {
+                                // TODO: Handle this
+                                future.completeExceptionally(new 
PlcException("Reading data type table failed: " + 
readDataTypeTableResponse.getResult()));
+                                return;
+                            }
+                            // Parse the result.
+                            ReadBuffer rb = new 
ReadBufferByteBased(readDataTypeTableResponse.getData());
+                            for (int i = 0; i < 
adsTableSizes.getDataTypeCount(); i++) {
+                                try {
+                                    AdsDataTypeTableEntry 
adsDataTypeTableEntry = AdsDataTypeTableEntry.staticParse(rb);
+                                    
dataTypeTable.put(adsDataTypeTableEntry.getDataTypeName(), 
adsDataTypeTableEntry);
+                                } catch (ParseException e) {
+                                    throw new RuntimeException(e);
+                                }
+                            }
+
+                            // Now we load the symbol definitions
+                            AmsPacket readSymbolTableRequest = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
+                                configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(), 0, getInvokeId(),
+                                
ReservedIndexGroups.ADSIGRP_SYM_UPLOAD.getValue(), 0x00000000, 
adsTableSizes.getSymbolLength());
+                            RequestTransactionManager.RequestTransaction 
readSymbolTableTx = tm.startRequest();
+                            AmsTCPPacket amsReadSymbolTableTCPPacket = new 
AmsTCPPacket(readSymbolTableRequest);
+                            readSymbolTableTx.submit(() -> 
context.sendRequest(amsReadSymbolTableTCPPacket)
+                                .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
+                                .onTimeout(future::completeExceptionally)
+                                .onError((p, e) -> 
future.completeExceptionally(e))
+                                .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
readSymbolTableRequest.getInvokeId())
+                                .unwrap(response -> (AdsReadResponse) 
response.getUserdata())
+                                .handle(readSymbolTableResponse -> {
+                                    readSymbolTableTx.endRequest();
+                                    if (readSymbolTableResponse.getResult() != 
ReturnCode.OK) {
+                                        // TODO: Handle this
+                                        future.completeExceptionally(new 
PlcException("Reading symbol table failed: " + 
readSymbolTableResponse.getResult()));
+                                        return;
+                                    }
+                                    ReadBuffer rb2 = new 
ReadBufferByteBased(readSymbolTableResponse.getData());
+                                    for (int i = 0; i < 
adsTableSizes.getSymbolCount(); i++) {
                                         try {
-                                            AdsDataTypeTableEntry 
adsDataTypeTableEntry = AdsDataTypeTableEntry.staticParse(rb);
-                                            
dataTypeTable.put(adsDataTypeTableEntry.getDataTypeName(), 
adsDataTypeTableEntry);
+                                            AdsSymbolTableEntry 
adsSymbolTableEntry = AdsSymbolTableEntry.staticParse(rb2);
+                                            
symbolTable.put(adsSymbolTableEntry.getName(), adsSymbolTableEntry);
                                         } catch (ParseException e) {
                                             throw new RuntimeException(e);
                                         }
                                     }
 
-                                    AmsPacket amsReadSymbolTablePacket = new 
AdsReadRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
-                                        configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(), 0, getInvokeId(),
-                                        
ReservedIndexGroups.ADSIGRP_SYM_UPLOAD.getValue(), 0x00000000, 
adsTableSizes.getSymbolLength());
-                                    
RequestTransactionManager.RequestTransaction transaction3 = tm.startRequest();
-                                    AmsTCPPacket amsReadSymbolTableTCPPacket = 
new AmsTCPPacket(amsReadSymbolTablePacket);
-                                    transaction3.submit(() -> 
context.sendRequest(amsReadSymbolTableTCPPacket)
-                                        .expectResponse(AmsTCPPacket.class, 
Duration.ofMillis(configuration.getTimeoutRequest()))
-                                        
.onTimeout(future::completeExceptionally)
-                                        .onError((p, e) -> 
future.completeExceptionally(e))
-                                        .check(responseAmsPacket -> 
responseAmsPacket.getUserdata().getInvokeId() == 
amsReadSymbolTablePacket.getInvokeId())
-                                        .unwrap(response -> (AdsReadResponse) 
response.getUserdata())
-                                        .handle(responseAdsReadSymbolTableData 
-> {
-                                            transaction3.endRequest();
-                                            if (responseAdsData.getResult() == 
ReturnCode.OK) {
-                                                ReadBuffer rb2 = new 
ReadBufferByteBased(responseAdsReadSymbolTableData.getData());
-                                                for (int i = 0; i < 
adsTableSizes.getSymbolCount(); i++) {
-                                                    try {
-                                                        AdsSymbolTableEntry 
adsSymbolTableEntry = AdsSymbolTableEntry.staticParse(rb2);
-                                                        
symbolTable.put(adsSymbolTableEntry.getName(), adsSymbolTableEntry);
-                                                    } catch (ParseException e) 
{
-                                                        throw new 
RuntimeException(e);
+                                    LinkedHashMap<String, 
PlcSubscriptionField> subscriptionFields = new LinkedHashMap<>();
+                                    // Subscribe to online-version changes 
(get the address from the collected data for symbol: 
"TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt")
+                                    subscriptionFields.put("onlineVersion", 
new DefaultPlcSubscriptionField(
+                                        PlcSubscriptionType.CHANGE_OF_STATE,
+                                        new 
SymbolicAdsField("TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"),
+                                        Duration.ofMillis(1000)));
+                                    // Subscribe to symbol-version changes 
(Address: GroupID: 0xF008, Offset: 0, Read length: 1)
+                                    subscriptionFields.put("symbolVersion", 
new DefaultPlcSubscriptionField(
+                                        PlcSubscriptionType.CHANGE_OF_STATE,
+                                        new DirectAdsField(0xF008, 0x0000, 
"USINT", 1),
+                                        Duration.ofMillis(1000)));
+                                    LinkedHashMap<String, 
List<Consumer<PlcSubscriptionEvent>>> consumer = new LinkedHashMap<>();
+                                    consumer.put("onlineVersion", 
Collections.singletonList(plcSubscriptionEvent -> {
+                                        long oldVersion = onlineVersion;
+                                        long newVersion = 
plcSubscriptionEvent.getPlcValue("onlineVersion").getLong();
+                                        if(oldVersion != newVersion) {
+                                            if(invalidationLock.tryLock()) {
+                                                LOGGER.info("Detected change 
of the 'online-version', invalidating data type and symbol information.");
+                                                CompletableFuture<Void> 
reloadingFuture = readSymbolTableAndDatatypeTable(context);
+                                                
reloadingFuture.whenComplete((unused, throwable) -> {
+                                                    if(throwable != null) {
+                                                        LOGGER.error("Error 
reloading data type and symbol data", throwable);
                                                     }
-                                                }
-                                                future.complete(null);
+                                                    invalidationLock.unlock();
+                                                });
                                             }
-                                        }));
-                                }
-                            }));
+                                        }
+                                    }));
+                                    consumer.put("symbolVersion", 
Collections.singletonList(plcSubscriptionEvent -> {
+                                        int oldVersion = symbolVersion;
+                                        int newVersion = 
plcSubscriptionEvent.getPlcValue("symbolVersion").getInteger();
+                                        if(oldVersion != newVersion) {
+                                            if(invalidationLock.tryLock()) {
+                                                LOGGER.info("Detected change 
of the 'symbol-version', invalidating data type and symbol information.");
+                                                CompletableFuture<Void> 
reloadingFuture = readSymbolTableAndDatatypeTable(context);
+                                                
reloadingFuture.whenComplete((unused, throwable) -> {
+                                                    if(throwable != null) {
+                                                        LOGGER.error("Error 
reloading data type and symbol data", throwable);
+                                                    }
+                                                    invalidationLock.unlock();
+                                                });
+                                            }
+                                        }
+                                    }));
+                                    PlcSubscriptionRequest subscriptionRequest 
= new DefaultPlcSubscriptionRequest(this, subscriptionFields, consumer);
+                                    CompletableFuture<PlcSubscriptionResponse> 
subscriptionResponseCompletableFuture = subscribe(subscriptionRequest);
+
+                                    // Wait for the subscription to be finished
+                                    
subscriptionResponseCompletableFuture.whenComplete((plcSubscriptionResponse, 
throwable) -> {
+                                        if(throwable == null) {
+                                            future.complete(null);
+                                        }
+                                    });
+                                }));
+                        }));
                     } catch (ParseException e) {
                         future.completeExceptionally(new PlcException("Error 
loading the table sizes", e));
                     }
-                } else {
-                    // TODO: Implement this correctly.
-                    future.completeExceptionally(new PlcException("Result is " 
+ responseAdsData.getResult()));
-                }
             }));
         return future;
     }
@@ -404,14 +557,14 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     @Override
     public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) 
{
         // Get all ADS addresses in their resolved state.
-        final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture =
+        final CompletableFuture<Map<AdsField, DirectAdsField>> 
directAdsFieldsFuture =
             getDirectAddresses(readRequest.getFields());
 
         // If all addresses were already resolved we can send the request 
immediately.
         if (directAdsFieldsFuture.isDone()) {
-            final List<DirectAdsField> fields = 
directAdsFieldsFuture.getNow(null);
-            if (fields != null) {
-                return executeRead(readRequest, fields);
+            final Map<AdsField, DirectAdsField> resolvedFields = 
directAdsFieldsFuture.getNow(null);
+            if (resolvedFields != null) {
+                return executeRead(readRequest, resolvedFields);
             } else {
                 final CompletableFuture<PlcReadResponse> errorFuture = new 
CompletableFuture<>();
                 errorFuture.completeExceptionally(new PlcException("Fields are 
null"));
@@ -448,15 +601,15 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     }
 
     protected CompletableFuture<PlcReadResponse> executeRead(PlcReadRequest 
readRequest,
-                                                             
List<DirectAdsField> directAdsFields) {
+                                                             Map<AdsField, 
DirectAdsField> resolvedFields) {
         // Depending on the number of fields, use a single item request or a 
sum-request
-        if (directAdsFields.size() == 1) {
+        if (resolvedFields.size() == 1) {
             // Do a normal (single item) ADS Read Request
-            return singleRead(readRequest, directAdsFields.get(0));
+            return singleRead(readRequest, 
resolvedFields.values().stream().findFirst().get());
         } else {
             // TODO: Check if the version of the remote station is at least 
TwinCAT v2.11 Build >= 1550 otherwise split up into single item requests.
             // Do a ADS-Sum Read Request.
-            return multiRead(readRequest, directAdsFields);
+            return multiRead(readRequest, resolvedFields);
         }
     }
 
@@ -495,12 +648,12 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         return future;
     }
 
-    protected CompletableFuture<PlcReadResponse> multiRead(PlcReadRequest 
readRequest, List<DirectAdsField> directAdsFields) {
+    protected CompletableFuture<PlcReadResponse> multiRead(PlcReadRequest 
readRequest, Map<AdsField, DirectAdsField> resolvedFields) {
         CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
 
         // Calculate the size of all fields together.
         // Calculate the expected size of the response data.
-        long expectedResponseDataSize = directAdsFields.stream().mapToLong(
+        long expectedResponseDataSize = 
resolvedFields.values().stream().mapToLong(
             field -> {
                 String dataTypeName = field.getAdsDataTypeName();
                 AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(dataTypeName);
@@ -512,15 +665,17 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         // With multi-requests, the index-group is fixed and the index offset 
indicates the number of elements.
         AmsPacket amsPacket = new 
AdsReadWriteRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
             configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(),
-            0, getInvokeId(), 
ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), directAdsFields.size(),
-            expectedResponseDataSize, 
directAdsFields.stream().map(directAdsField -> {
-            String dataTypeName = directAdsField.getAdsDataTypeName();
-            AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(dataTypeName);
-            long size = adsDataTypeTableEntry.getSize();
-            return new AdsMultiRequestItemRead(
-                directAdsField.getIndexGroup(), 
directAdsField.getIndexOffset(),
-                (size * directAdsField.getNumberOfElements()));
-        }).collect(Collectors.toList()), null);
+            0, getInvokeId(), 
ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), resolvedFields.size(),
+            expectedResponseDataSize, 
readRequest.getFieldNames().stream().map(fieldName -> {
+                AdsField field = (AdsField) readRequest.getField(fieldName);
+                DirectAdsField directAdsField = resolvedFields.get(field);
+                String dataTypeName = directAdsField.getAdsDataTypeName();
+                AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(dataTypeName);
+                long size = adsDataTypeTableEntry.getSize();
+                return new AdsMultiRequestItemRead(
+                    directAdsField.getIndexGroup(), 
directAdsField.getIndexOffset(),
+                    (size * directAdsField.getNumberOfElements()));
+            }).collect(Collectors.toList()), null);
         AmsTCPPacket amsTCPPacket = new AmsTCPPacket(amsPacket);
 
         // Start a new request-transaction (Is ended in the response-handler)
@@ -561,7 +716,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         } else if (adsData instanceof AdsReadWriteResponse) {
             AdsReadWriteResponse adsReadWriteResponse = (AdsReadWriteResponse) 
adsData;
             readBuffer = new 
ReadBufferByteBased(adsReadWriteResponse.getData(), ByteOrder.LITTLE_ENDIAN);
-            // When parsing a multi-item response, the error codes of each 
items come
+            // When parsing a multi-item response, the error codes of each 
item comes
             // in sequence and then come the values.
             for (String fieldName : readRequest.getFieldNames()) {
                 try {
@@ -613,7 +768,8 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
 
             int strLen = 0;
             if ((plcValueType == PlcValueType.STRING) || (plcValueType == 
PlcValueType.WSTRING)) {
-                strLen = (field instanceof AdsStringField) ? ((AdsStringField) 
field).getStringLength() : 256;
+                // Extract the string length from the data type name.
+                strLen = 
Integer.parseInt(dataTypeName.substring(dataTypeName.indexOf("(") + 1, 
dataTypeName.indexOf(")")));
             }
             final int stringLength = strLen;
             if (field.getNumberOfElements() == 1) {
@@ -693,14 +849,14 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     @Override
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest 
writeRequest) {
         // Get all ADS addresses in their resolved state.
-        final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture =
+        final CompletableFuture<Map<AdsField, DirectAdsField>> 
directAdsFieldsFuture =
             getDirectAddresses(writeRequest.getFields());
 
         // If all addresses were already resolved we can send the request 
immediately.
         if (directAdsFieldsFuture.isDone()) {
-            final List<DirectAdsField> fields = 
directAdsFieldsFuture.getNow(null);
-            if (fields != null) {
-                return executeWrite(writeRequest, fields);
+            final Map<AdsField, DirectAdsField> resolvedFields = 
directAdsFieldsFuture.getNow(null);
+            if (resolvedFields != null) {
+                return executeWrite(writeRequest, resolvedFields);
             } else {
                 final CompletableFuture<PlcWriteResponse> errorFuture = new 
CompletableFuture<>();
                 errorFuture.completeExceptionally(new PlcException("Fields are 
null"));
@@ -738,15 +894,15 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     }
 
     protected CompletableFuture<PlcWriteResponse> executeWrite(PlcWriteRequest 
writeRequest,
-                                                               
List<DirectAdsField> directAdsFields) {
+                                                               Map<AdsField, 
DirectAdsField> resolvedFields) {
         // Depending on the number of fields, use a single item request or a 
sum-request
-        if (directAdsFields.size() == 1) {
+        if (resolvedFields.size() == 1) {
             // Do a normal (single item) ADS Write Request
-            return singleWrite(writeRequest, directAdsFields.get(0));
+            return singleWrite(writeRequest, 
resolvedFields.values().stream().findFirst().get());
         } else {
             // TODO: Check if the version of the remote station is at least 
TwinCAT v2.11 Build >= 1550 otherwise split up into single item requests.
             // Do a ADS-Sum Read Request.
-            return multiWrite(writeRequest, directAdsFields);
+            return multiWrite(writeRequest, resolvedFields);
         }
     }
 
@@ -801,7 +957,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         return future;
     }
 
-    protected CompletableFuture<PlcWriteResponse> multiWrite(PlcWriteRequest 
writeRequest, List<DirectAdsField> directAdsFields) {
+    protected CompletableFuture<PlcWriteResponse> multiWrite(PlcWriteRequest 
writeRequest, Map<AdsField, DirectAdsField> resolvedFields) {
         CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
 
         // Calculate the size of all fields together.
@@ -896,7 +1052,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     @Override
     public CompletableFuture<PlcSubscriptionResponse> 
subscribe(PlcSubscriptionRequest subscriptionRequest) {
         // Get all ADS addresses in their resolved state.
-        final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture =
+        final CompletableFuture<Map<AdsField, DirectAdsField>> 
directAdsFieldsFuture =
             getDirectAddresses(subscriptionRequest.getFields()
                 .stream()
                 .map(field -> ((DefaultPlcSubscriptionField) 
field).getPlcField())
@@ -904,9 +1060,9 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
 
         // If all addresses were already resolved we can send the request 
immediately.
         if (directAdsFieldsFuture.isDone()) {
-            final List<DirectAdsField> fields = 
directAdsFieldsFuture.getNow(null);
-            if (fields != null) {
-                return executeSubscribe(subscriptionRequest);
+            final Map<AdsField, DirectAdsField> resolvedFields = 
directAdsFieldsFuture.getNow(null);
+            if (resolvedFields != null) {
+                return executeSubscribe(subscriptionRequest, resolvedFields);
             } else {
                 final CompletableFuture<PlcSubscriptionResponse> errorFuture = 
new CompletableFuture<>();
                 errorFuture.completeExceptionally(new PlcException("Fields are 
null"));
@@ -922,10 +1078,10 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         // we can complete the initial one.
         else {
             CompletableFuture<PlcSubscriptionResponse> delayedSubscribe = new 
CompletableFuture<>();
-            directAdsFieldsFuture.handle((directAdsFields, throwable) -> {
-                if (directAdsFields != null) {
+            directAdsFieldsFuture.handle((fieldMapping, throwable) -> {
+                if (fieldMapping != null) {
                     final CompletableFuture<PlcSubscriptionResponse> 
delayedResponse =
-                        executeSubscribe(subscriptionRequest);
+                        executeSubscribe(subscriptionRequest, fieldMapping);
                     delayedResponse.handle((plcSubscribeResponse, throwable1) 
-> {
                         if (plcSubscribeResponse != null) {
                             delayedSubscribe.complete(plcSubscribeResponse);
@@ -943,14 +1099,14 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         }
     }
 
-    private CompletableFuture<PlcSubscriptionResponse> 
executeSubscribe(PlcSubscriptionRequest subscribeRequest) {
+    private CompletableFuture<PlcSubscriptionResponse> 
executeSubscribe(PlcSubscriptionRequest subscribeRequest, Map<AdsField, 
DirectAdsField> resolvedFields) {
         CompletableFuture<PlcSubscriptionResponse> future = new 
CompletableFuture<>();
 
         List<AmsTCPPacket> amsTCPPackets = 
subscribeRequest.getFields().stream()
             .map(field -> (DefaultPlcSubscriptionField) field)
             .map(field -> {
-                AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(((DirectAdsField) field.getPlcField()).getAdsDataTypeName());
-                DirectAdsField directAdsField = 
getDirectAdsFieldForSymbolicName(field);
+                AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(resolvedFields.get((AdsField) 
field.getPlcField()).getAdsDataTypeName());
+                DirectAdsField directAdsField = 
getDirectAdsFieldForSymbolicName(field.getPlcField());
                 return new AmsTCPPacket(new 
AdsAddDeviceNotificationRequest(configuration.getTargetAmsNetId(), 
configuration.getTargetAmsPort(),
                     configuration.getSourceAmsNetId(), 
configuration.getSourceAmsPort(),
                     0, getInvokeId(),
@@ -970,6 +1126,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         transaction.submit(subscribeRecursively(
             subscribeRequest,
             subscribeRequest.getFieldNames().iterator(),
+            resolvedFields,
             responses,
             future,
             amsTCPPackets.iterator(),
@@ -977,7 +1134,9 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         return future;
     }
 
-    private Runnable subscribeRecursively(PlcSubscriptionRequest 
subscriptionRequest, Iterator<String> fieldNames,
+    private Runnable subscribeRecursively(PlcSubscriptionRequest 
subscriptionRequest,
+                                          Iterator<String> fieldNames,
+                                          Map<AdsField, DirectAdsField> 
resolvedFields,
                                           Map<String, 
ResponseItem<PlcSubscriptionHandle>> responses,
                                           
CompletableFuture<PlcSubscriptionResponse> future,
                                           Iterator<AmsTCPPacket> amsTCPPackets,
@@ -995,7 +1154,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
                 .handle(response -> {
                     if (response.getResult() == ReturnCode.OK) {
                         DefaultPlcSubscriptionField subscriptionField = 
(DefaultPlcSubscriptionField) subscriptionRequest.getField(fieldName);
-                        AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(((DirectAdsField) 
subscriptionField.getPlcField()).getAdsDataTypeName());
+                        AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get((resolvedFields.get((AdsField) 
subscriptionField.getPlcField())).getAdsDataTypeName());
 
                         // Collect notification handle from individual 
response.
                         responses.put(fieldName, new ResponseItem<>(
@@ -1025,7 +1184,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
                     if (hasMorePackets) {
                         RequestTransactionManager.RequestTransaction 
nextTransaction = tm.startRequest();
                         nextTransaction.submit(subscribeRecursively(
-                            subscriptionRequest, fieldNames, responses, 
future, amsTCPPackets, nextTransaction));
+                            subscriptionRequest, fieldNames, resolvedFields, 
responses, future, amsTCPPackets, nextTransaction));
                     }
                 });
         };
@@ -1150,8 +1309,8 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         consumers.remove(consumerRegistration);
     }
 
-    protected CompletableFuture<List<DirectAdsField>> 
getDirectAddresses(List<PlcField> fields) {
-        CompletableFuture<List<DirectAdsField>> future = new 
CompletableFuture<>();
+    protected CompletableFuture<Map<AdsField, DirectAdsField>> 
getDirectAddresses(List<PlcField> fields) {
+        CompletableFuture<Map<AdsField, DirectAdsField>> future = new 
CompletableFuture<>();
 
         // Get all symbolic fields from the current request.
         // These potentially need to be resolved to direct addresses, if this 
has not been done before.
@@ -1202,26 +1361,28 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
                 if (throwable != null) {
                     return future.completeExceptionally(throwable.getCause());
                 } else {
-                    List<DirectAdsField> directAdsFields = new 
ArrayList<>(fields.size());
+                    Map<AdsField, DirectAdsField> directAdsFieldMapping = new 
HashMap<>(fields.size());
                     for (PlcField field : fields) {
                         if (field instanceof SymbolicAdsField) {
-                            
directAdsFields.add(getDirectAdsFieldForSymbolicName(field));
+                            directAdsFieldMapping.put((AdsField) field, 
getDirectAdsFieldForSymbolicName(field));
                         } else {
-                            directAdsFields.add((DirectAdsField) field);
+                            directAdsFieldMapping.put((AdsField) field, 
(DirectAdsField) field);
                         }
                     }
-                    return future.complete(directAdsFields);
+                    return future.complete(directAdsFieldMapping);
                 }
             });
         } else {
             // If all fields were resolved, we can continue instantly.
-            future.complete(fields.stream().map(plcField -> {
-                if (plcField instanceof SymbolicAdsField) {
-                    return getDirectAdsFieldForSymbolicName(plcField);
+            Map<AdsField, DirectAdsField> directAdsFieldMapping = new 
HashMap<>(fields.size());
+            for (PlcField field : fields) {
+                if (field instanceof SymbolicAdsField) {
+                    directAdsFieldMapping.put((AdsField) field, 
getDirectAdsFieldForSymbolicName(field));
                 } else {
-                    return (DirectAdsField) plcField;
+                    directAdsFieldMapping.put((AdsField) field, 
(DirectAdsField) field);
                 }
-            }).collect(Collectors.toList()));
+            }
+            future.complete(directAdsFieldMapping);
         }
         return future;
     }
@@ -1364,9 +1525,16 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
             if (!symbolTable.containsKey(symbolicAddress)) {
                 return null;
             }
-
             AdsSymbolTableEntry adsSymbolTableEntry = 
symbolTable.get(symbolicAddress);
+            if(adsSymbolTableEntry == null) {
+                throw new PlcInvalidFieldException("Couldn't resolve symbolic 
address: " + symbolicAddress);
+            }
             AdsDataTypeTableEntry dataTypeTableEntry = 
dataTypeTable.get(adsSymbolTableEntry.getDataTypeName());
+            if(dataTypeTableEntry == null) {
+                throw new PlcInvalidFieldException(
+                    "Couldn't resolve datatype: '" + 
adsSymbolTableEntry.getDataTypeName() +
+                        "' for address: '" + ((SymbolicAdsField) 
field).getSymbolicAddress() + "'");
+            }
             return new DirectAdsField(adsSymbolTableEntry.getGroup(), 
adsSymbolTableEntry.getOffset(),
                 dataTypeTableEntry.getDataTypeName(), 
dataTypeTableEntry.getArrayDimensions());
         }
@@ -1374,7 +1542,15 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
         else {
             String symbolName = addressParts[0] + "." + addressParts[1];
             AdsSymbolTableEntry adsSymbolTableEntry = 
symbolTable.get(symbolName);
+            if(adsSymbolTableEntry == null) {
+                throw new PlcInvalidFieldException("Couldn't resolve symbolic 
address: " + symbolName);
+            }
             AdsDataTypeTableEntry adsDataTypeTableEntry = 
dataTypeTable.get(adsSymbolTableEntry.getDataTypeName());
+            if(adsDataTypeTableEntry == null) {
+                throw new PlcInvalidFieldException(
+                    "Couldn't resolve datatype: '" + 
adsSymbolTableEntry.getDataTypeName() +
+                        "' for address: '" + ((SymbolicAdsField) 
field).getSymbolicAddress() + "'");
+            }
             return resolveDirectAdsFieldForSymbolicNameFromDataType(
                 Arrays.asList(addressParts).subList(2, addressParts.length),
                 adsSymbolTableEntry.getGroup(), 
adsSymbolTableEntry.getOffset(), adsDataTypeTableEntry);
@@ -1384,7 +1560,7 @@ public class AdsProtocolLogic extends 
Plc4xProtocolBase<AmsTCPPacket> implements
     protected DirectAdsField 
resolveDirectAdsFieldForSymbolicNameFromDataType(List<String> 
remainingAddressParts, long currentGroup, long currentOffset, 
AdsDataTypeTableEntry adsDataTypeTableEntry) {
         if (remainingAddressParts.isEmpty()) {
             // TODO: Implement the Array support
-            return new DirectAdsField(currentGroup, currentOffset, 
adsDataTypeTableEntry.getDataTypeName(), null);
+            return new DirectAdsField(currentGroup, currentOffset, 
adsDataTypeTableEntry.getDataTypeName(), 1);
         }
 
         // Go through all children looking for a matching one.
diff --git 
a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java
 
b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java
deleted file mode 100644
index f0b874735..000000000
--- 
a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.plc4x.java.ads.readwrite.utils;
-
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
-
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-public class StaticHelper {
-
-    public static String parseAmsString(ReadBuffer readBuffer, int 
stringLength, String encoding) {
-        try {
-            if ("UTF-8".equalsIgnoreCase(encoding)) {
-                List<Byte> bytes = new ArrayList<>();
-                for(int i = 0; (i < stringLength) && readBuffer.hasMore(8); 
i++) {
-                    final byte curByte = readBuffer.readByte();
-                    if (curByte != 0) {
-                        bytes.add(curByte);
-                    } else {
-                        // Gobble up the remaining data, which is not added to 
the string.
-                        i++;
-                        for(; (i < stringLength) && readBuffer.hasMore(8); 
i++) {
-                            readBuffer.readByte();
-                        }
-                        break;
-                    }
-                }
-                // Read the terminating byte.
-                readBuffer.readByte();
-                final byte[] byteArray = new byte[bytes.size()];
-                for (int i = 0; i < bytes.size(); i++) {
-                    byteArray[i] = bytes.get(i);
-                }
-                return new String(byteArray, StandardCharsets.UTF_8);
-            } else if ("UTF-16".equalsIgnoreCase(encoding)) {
-                List<Byte> bytes = new ArrayList<>();
-                for(int i = 0; (i < stringLength) && readBuffer.hasMore(16); 
i++) {
-                    final short curShort = readBuffer.readShort(16);
-                    if (curShort != 0) {
-                        bytes.add((byte) (curShort >>> 8));
-                        bytes.add((byte) (curShort & 0xFF));
-                    } else {
-                        // Gobble up the remaining data, which is not added to 
the string.
-                        i++;
-                        for(; (i < stringLength) && readBuffer.hasMore(16); 
i++) {
-                            readBuffer.readShort(16);
-                        }
-                        break;
-                    }
-                }
-                // Read the terminating byte.
-                readBuffer.readByte();
-                final byte[] byteArray = new byte[bytes.size()];
-                for (int i = 0; i < bytes.size(); i++) {
-                    byteArray[i] = bytes.get(i);
-                }
-                return new String(byteArray, StandardCharsets.UTF_16);
-            } else {
-                throw new PlcRuntimeException("Unsupported string encoding " + 
encoding);
-            }
-        } catch (ParseException e) {
-            throw new PlcRuntimeException("Error parsing string", e);
-        }
-    }
-
-    public static void serializeAmsString(WriteBuffer writeBuffer, PlcValue 
value, int stringLength, Object encoding) {
-        // TODO: Need to implement the serialization or we can't write strings
-        throw new PlcRuntimeException("Not implemented yet");
-    }
-
-}
diff --git 
a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
 
b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
index 8f9d25e64..d89a68d95 100644
--- 
a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
+++ 
b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java
@@ -69,40 +69,36 @@ public class ManualAdsDriverTest extends ManualTest {
 
     public static void main(String[] args) throws Exception {
         String spsIp = "192.168.23.20";
-        /////
-        // TODO: adjust this to your ip address
         String clientIp = "192.168.23.200";
-        //
-        ////
         String sourceAmsNetId = clientIp + ".1.1";
         int sourceAmsPort = 65534;
         String targetAmsNetId = spsIp + ".1.1";
         int targetAmsPort = 851;
         String connectionString = 
String.format("ads:tcp://%s?sourceAmsNetId=%s&sourceAmsPort=%d&targetAmsNetId=%s&targetAmsPort=%d",
 spsIp, sourceAmsNetId, sourceAmsPort, targetAmsNetId, targetAmsPort);
         ManualAdsDriverTest test = new ManualAdsDriverTest(connectionString);
-        test.addTestCase("main.hurz_BOOL:BOOL", true);
-        test.addTestCase("main.hurz_BYTE:BYTE", Arrays.asList(false, false, 
true, false, true, false, true, false));
-        test.addTestCase("main.hurz_WORD:WORD", Arrays.asList(true, false, 
true, false, false, true, false, true, true, false, true, true, true, false, 
false, false));
-        test.addTestCase("main.hurz_DWORD:DWORD", Arrays.asList(true, true, 
true, true, true, true, false, false, true, true, false, true, true, true, 
true, false, true, false, false, false, true, false, false, false, true, false, 
true, true, true, false, false, false));
-        test.addTestCase("main.hurz_SINT:SINT", -42);
-        test.addTestCase("main.hurz_USINT:USINT", 42);
-        test.addTestCase("main.hurz_INT:INT", -2424);
-        test.addTestCase("main.hurz_UINT:UINT", 42424);
-        test.addTestCase("main.hurz_DINT:DINT", -242442424);
-        test.addTestCase("main.hurz_UDINT:UDINT", 4242442424L);
-        test.addTestCase("main.hurz_LINT:LINT", -4242442424242424242L);
-        test.addTestCase("main.hurz_ULINT:ULINT", 4242442424242424242L);
-        test.addTestCase("main.hurz_REAL:REAL", 3.14159265359F);
-        test.addTestCase("main.hurz_LREAL:LREAL", 2.71828182846D);
-        test.addTestCase("main.hurz_STRING:STRING", "hurz");
-        test.addTestCase("main.hurz_WSTRING:WSTRING", "wolf");
-        test.addTestCase("main.hurz_TIME:TIME", "PT1.234S");
-        test.addTestCase("main.hurz_LTIME:LTIME", "PT24015H23M12.034002044S");
-        test.addTestCase("main.hurz_DATE:DATE", "1978-03-28");
-        test.addTestCase("main.hurz_TIME_OF_DAY:TIME_OF_DAY", "15:36:30.123");
-        test.addTestCase("main.hurz_TOD:TOD", "16:17:18.123");
-        test.addTestCase("main.hurz_DATE_AND_TIME:DATE_AND_TIME", 
"1996-05-06T15:36:30");
-        test.addTestCase("main.hurz_DT:DT", "1972-03-29T00:00");
+        test.addTestCase("MAIN.hurz_BOOL", true);
+        test.addTestCase("MAIN.hurz_BYTE", Arrays.asList(false, false, true, 
false, true, false, true, false));
+        test.addTestCase("MAIN.hurz_WORD", Arrays.asList(true, false, true, 
false, false, true, false, true, true, false, true, true, true, false, false, 
false));
+        test.addTestCase("MAIN.hurz_DWORD", Arrays.asList(true, true, true, 
true, true, true, false, false, true, true, false, true, true, true, true, 
false, true, false, false, false, true, false, false, false, true, false, true, 
true, true, false, false, false));
+        test.addTestCase("MAIN.hurz_SINT", -42);
+        test.addTestCase("MAIN.hurz_USINT", 42);
+        test.addTestCase("MAIN.hurz_INT", -2424);
+        test.addTestCase("MAIN.hurz_UINT", 42424);
+        test.addTestCase("MAIN.hurz_DINT", -242442424);
+        test.addTestCase("MAIN.hurz_UDINT", 4242442424L);
+        test.addTestCase("MAIN.hurz_LINT", -4242442424242424242L);
+        test.addTestCase("MAIN.hurz_ULINT", 4242442424242424242L);
+        test.addTestCase("MAIN.hurz_REAL", 3.14159265359F);
+        test.addTestCase("MAIN.hurz_LREAL", 2.71828182846D);
+        test.addTestCase("MAIN.hurz_STRING", "hurz");
+        test.addTestCase("MAIN.hurz_WSTRING", "wolf");
+        test.addTestCase("MAIN.hurz_TIME", "PT1.234S");
+        test.addTestCase("MAIN.hurz_LTIME", "PT24015H23M12.034002044S");
+        test.addTestCase("MAIN.hurz_DATE", "1978-03-28");
+        test.addTestCase("MAIN.hurz_TIME_OF_DAY", "15:36:30.123");
+        test.addTestCase("MAIN.hurz_TOD", "16:17:18.123");
+        test.addTestCase("MAIN.hurz_DATE_AND_TIME", "1996-05-06T15:36:30");
+        test.addTestCase("MAIN.hurz_DT", "1972-03-29T00:00");
         test.run();
     }
 
diff --git 
a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
 
b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
index 5aff2986d..87b016139 100644
--- 
a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
+++ 
b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java
@@ -48,7 +48,7 @@ public class StaticHelper {
         // NOOP - a placeholder to let mspec compile
     }
 
-    public static Object parseString(ReadBuffer io, int length, String 
charset) {
+    public static Object parseString(ReadBuffer io, int length, String 
charset) throws ParseException {
         return io.readString(8 * length, charset);
     }
 
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
index 054e1c7b8..660aa7a4f 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java
@@ -1930,7 +1930,7 @@ public class StaticHelper {
         throw new NotImplementedException("Serializing DATE_AND_TIME not 
implemented");
     }
 
-    public static String parseS7Char(ReadBuffer io, String encoding) {
+    public static String parseS7Char(ReadBuffer io, String encoding) throws 
ParseException {
         if ("UTF-8".equalsIgnoreCase(encoding)) {
             return io.readString(8, encoding);
         } else if ("UTF-16".equalsIgnoreCase(encoding)) {
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 79ccaec5b..663a43c78 100644
--- 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -128,9 +128,9 @@ public interface ReadBuffer extends ByteOrderAware, 
PositionAware {
         return readBigDecimal("", bitLength);
     }
 
-    String readString(String logicalName, int bitLength, String encoding, 
WithReaderArgs... readerArgs);
+    String readString(String logicalName, int bitLength, String encoding, 
WithReaderArgs... readerArgs) throws ParseException;
 
-    default String readString(int bitLength, String encoding) {
+    default String readString(int bitLength, String encoding) throws 
ParseException {
         return readString("", bitLength, encoding);
     }
 
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
index 8c90ac6e8..6afe32f14 100644
--- 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
+++ 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
 public class ReadBufferByteBased implements ReadBuffer {
@@ -321,7 +322,7 @@ public class ReadBufferByteBased implements ReadBuffer {
         if(sign) {
             fraction = (short) (fraction | 0xF800);
         }
-        if ((exponent >= 1) && (exponent <= 15)) {
+        if ((exponent >= 1) && (exponent < 15)) {
             return (float) (0.01 * fraction * Math.pow(2, exponent));
         }
         if (exponent == 0) {
@@ -388,17 +389,65 @@ public class ReadBufferByteBased implements ReadBuffer {
     }
 
     @Override
-    public String readString(String logicalName, int bitLength, String 
encoding, WithReaderArgs... readerArgs) {
-        byte[] strBytes = new byte[bitLength / 8];
-        for (int i = 0; (i < (bitLength / 8)) && hasMore(8); i++) {
-            try {
-                strBytes[i] = readByte(logicalName);
-            } catch (Exception e) {
-                throw new PlcRuntimeException(e);
+    public String readString(String logicalName, int bitLength, String 
encoding, WithReaderArgs... readerArgs) throws ParseException {
+        encoding = encoding.replaceAll("[^a-zA-Z0-9]", "");
+        switch (encoding.toUpperCase()) {
+            case "UTF8": {
+                byte[] strBytes = new byte[bitLength / 8];
+                int realLength = 0;
+                boolean finishedReading = false;
+                for (int i = 0; (i < (bitLength / 8)) && hasMore(8); i++) {
+                    try {
+                        byte b = readByte(logicalName);
+                        if (b == 0x00) {
+                            finishedReading = true;
+                        } else if (!finishedReading) {
+                            strBytes[i] = b;
+                            realLength++;
+                        }
+                    } catch (Exception e) {
+                        throw new PlcRuntimeException(e);
+                    }
+                }
+                return new String(strBytes, 
StandardCharsets.UTF_8).substring(0, realLength);
             }
+            case "UTF16":
+            case "UTF16LE":
+            case "UTF16BE": {
+                byte[] strBytes = new byte[bitLength / 8];
+                int realLength = 0;
+                boolean finishedReading = false;
+                for (int i = 0; (i < (bitLength / 16)) && hasMore(16); i++) {
+                    try {
+                        byte b1 = readByte(logicalName);
+                        byte b2 = readByte(logicalName);
+                        if ((b1 == 0x00) && (b2 == 0x00)) {
+                            finishedReading = true;
+                        } else if (!finishedReading){
+                            strBytes[(i * 2)] = b1;
+                            strBytes[(i * 2) + 1] = b2;
+                            realLength++;
+                        }
+                    } catch (Exception e) {
+                        throw new PlcRuntimeException(e);
+                    }
+                }
+                Charset charset;
+                switch (encoding) {
+                    case "UTF16LE":
+                        charset = StandardCharsets.UTF_16LE;
+                        break;
+                    case "UTF16BE":
+                        charset = StandardCharsets.UTF_16BE;
+                        break;
+                    default:
+                        charset = StandardCharsets.UTF_16;
+                }
+                return new String(strBytes, charset).substring(0, realLength);
+            }
+            default:
+                throw new ParseException("Unsupported encoding: " + encoding);
         }
-        //replaceAll function removes and leading ' char or hypens.
-        return new String(strBytes, 
Charset.forName(encoding.replaceAll("[^a-zA-Z0-9]", "")));
     }
 
 
diff --git 
a/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java
 
b/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java
index 757a0b30d..aeb6d60a4 100644
--- 
a/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java
+++ 
b/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java
@@ -30,7 +30,7 @@ class ReadBufferTest {
      * Test which makes sure that PLC4X-256 is not happening.
      */
     @Test
-    void readString() {
+    void readString() throws ParseException {
         String value = new String("abcdef");
         final ReadBuffer buffer = new 
ReadBufferByteBased(value.getBytes(StandardCharsets.UTF_8));
         String answer = buffer.readString("", value.length() * 8, "UTF-8");
diff --git 
a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
 
b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index e74b5ed9c..5f70844b9 100644
--- 
a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ 
b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -137,7 +137,7 @@ public class StaticHelper {
         throw new NotImplementedException("Serializing STRING not 
implemented");
     }
 
-    public static String parseS7Char(ReadBuffer io, Object encoding) {
+    public static String parseS7Char(ReadBuffer io, Object encoding) throws 
ParseException {
         // Read the full size of the string.
         return io.readString(8, (String) encoding);
     }
diff --git 
a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
 
b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
index b5ab8eb8a..92e4733c3 100644
--- 
a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
+++ 
b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java
@@ -91,7 +91,7 @@ public abstract class ManualTest {
                 for (TestCase testCase : shuffledTestcases) {
                     sb.append(testCase.address).append(", ");
                 }
-                System.out.println("       using order: " + sb.toString());
+                System.out.println("       using order: " + sb);
 
                 final PlcReadRequest.Builder builder = 
plcConnection.readRequestBuilder();
                 for (TestCase testCase : shuffledTestcases) {
@@ -107,17 +107,20 @@ public abstract class ManualTest {
                 Assertions.assertEquals(shuffledTestcases.size(), 
readResponse.getFieldNames().size());
                 for (TestCase testCase : shuffledTestcases) {
                     String fieldName = testCase.address;
-                    Assertions.assertEquals(PlcResponseCode.OK, 
readResponse.getResponseCode(fieldName));
-                    
Assertions.assertNotNull(readResponse.getPlcValue(fieldName));
+                    Assertions.assertEquals(PlcResponseCode.OK, 
readResponse.getResponseCode(fieldName),
+                        "Field: " + fieldName);
+                    
Assertions.assertNotNull(readResponse.getPlcValue(fieldName), "Field: " + 
fieldName);
                     if (readResponse.getPlcValue(fieldName) instanceof 
PlcList) {
                         PlcList plcList = (PlcList) 
readResponse.getPlcValue(fieldName);
                         List<Object> expectedValues = (List<Object>) 
testCase.expectedReadValue;
                         for (int j = 0; j < expectedValues.size(); j++) {
-                            Assertions.assertEquals(expectedValues.get(j), 
plcList.getIndex(j).getObject());
+                            Assertions.assertEquals(expectedValues.get(j), 
plcList.getIndex(j).getObject(),
+                                "Field: " + fieldName);
                         }
                     } else {
                         Assertions.assertEquals(
-                            testCase.expectedReadValue.toString(), 
readResponse.getPlcValue(fieldName).getObject().toString());
+                            testCase.expectedReadValue.toString(), 
readResponse.getPlcValue(fieldName).getObject().toString(),
+                            "Field: " + fieldName);
                     }
                 }
             }
diff --git 
a/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs
 
b/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs
index ae91c3575..59306feb1 100644
--- 
a/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs
+++ 
b/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs
@@ -623,8 +623,9 @@ namespace 
org.apache.plc4net.drivers.knxnetip.readwrite.model
         M_GUANGDONG_KANWAY = 596,
         M_PHOENIX_CONTACT_2 = 597,
         M_RAMIREZ_ENGINEERING_GMBH = 598,
-        M_ABB___RESERVED = 599,
-        M_BUSCH_JAEGER_ELEKTRO___RESERVED = 600,
+        M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD = 599,
+        M_ABB___RESERVED = 600,
+        M_BUSCH_JAEGER_ELEKTRO___RESERVED = 601,
     }
 
     public static class KnxManufacturerInfo
@@ -2299,8 +2300,8 @@ namespace 
org.apache.plc4net.drivers.knxnetip.readwrite.model
                 case KnxManufacturer.M_RAMIREZ_ENGINEERING_GMBH: { /* '598' */
                     return 656;
                 }
-                case KnxManufacturer.M_ABB___RESERVED: { /* '599' */
-                    return 43954;
+                case KnxManufacturer.M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD: { 
/* '599' */
+                    return 657;
                 }
                 case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO: { /* '6' */
                     return 7;
@@ -2308,7 +2309,10 @@ namespace 
org.apache.plc4net.drivers.knxnetip.readwrite.model
                 case KnxManufacturer.M_TECHEM: { /* '60' */
                     return 99;
                 }
-                case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* 
'600' */
+                case KnxManufacturer.M_ABB___RESERVED: { /* '600' */
+                    return 43954;
+                }
+                case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* 
'601' */
                     return 43959;
                 }
                 case KnxManufacturer.M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS: { /* 
'61' */
@@ -4112,8 +4116,8 @@ namespace 
org.apache.plc4net.drivers.knxnetip.readwrite.model
                 case KnxManufacturer.M_RAMIREZ_ENGINEERING_GMBH: { /* '598' */
                     return "RAMIREZ Engineering GmbH";
                 }
-                case KnxManufacturer.M_ABB___RESERVED: { /* '599' */
-                    return "ABB - reserved";
+                case KnxManufacturer.M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD: { 
/* '599' */
+                    return "Zhongshan Taiyang IMP&EXP. CO LTD";
                 }
                 case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO: { /* '6' */
                     return "Busch-Jaeger Elektro";
@@ -4121,7 +4125,10 @@ namespace 
org.apache.plc4net.drivers.knxnetip.readwrite.model
                 case KnxManufacturer.M_TECHEM: { /* '60' */
                     return "Techem";
                 }
-                case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* 
'600' */
+                case KnxManufacturer.M_ABB___RESERVED: { /* '600' */
+                    return "ABB - reserved";
+                }
+                case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* 
'601' */
                     return "Busch-Jaeger Elektro - reserved";
                 }
                 case KnxManufacturer.M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS: { /* 
'61' */
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec 
b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index d1ce4bee6..284835ac0 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -458,15 +458,15 @@
             [simple string 8 value]
         ]
         ['WCHAR' STRING
-            [simple string 16 value encoding='"UTF-16"']
+            [simple string 16 value encoding='"UTF-16LE"']
         ]
         ['STRING' STRING
-            // TODO: Fix this length
-            [manual vstring value 'STATIC_CALL("parseAmsString", readBuffer, 
stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, 
_value, stringLength, _type.encoding)' 'stringLength + 1']
+            [simple   vstring 'stringLength * 8' value ]
+            [reserved uint 8                    '0x00']
         ]
         ['WSTRING' STRING
-            // TODO: Fix this length
-            [manual vstring value 'STATIC_CALL("parseAmsString", readBuffer, 
stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, 
_value, stringLength, _type.encoding)' '(stringLength * 2) + 2' 
encoding='"UTF-16"']
+            [simple   vstring 'stringLength * 8 * 2' value    
encoding='"UTF-16LE"']
+            [reserved uint 16                        '0x0000'                  
    ]
         ]
 
         // -----------------------------------------

Reply via email to