feat(plc4j/modbus) Add support for modbus identification requests.

Reorganization of modbus fields, so identification request might be a Struct.
Additionally, fixes for unbalanced stack operations in PlcStruct.

Signed-off-by: Łukasz Dywicki <luke@code-house.org>
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
index 63a54f2..7a5f3a2 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
@@ -27,10 +27,9 @@
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.modbus.ascii.config.ModbusAsciiConfiguration;
-import org.apache.plc4x.java.modbus.base.field.ModbusField;
+import org.apache.plc4x.java.modbus.base.field.ModbusFieldBase;
 import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
 import org.apache.plc4x.java.modbus.readwrite.*;
-import org.apache.plc4x.java.modbus.rtu.config.ModbusRtuConfiguration;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
@@ -74,7 +73,7 @@
         // Example for sending a request ...
         if (request.getFieldNames().size() == 1) {
             String fieldName = request.getFieldNames().iterator().next();
-            ModbusField field = (ModbusField) request.getField(fieldName);
+            ModbusFieldBase field = (ModbusFieldBase) request.getField(fieldName);
             final ModbusPDU requestPdu = getReadRequestPdu(field);
 
             ModbusAsciiADU modbusAsciiADU = new ModbusAsciiADU(unitIdentifier, requestPdu, false);
@@ -94,7 +93,7 @@
                         responseCode = getErrorCode(errorResponse);
                     } else {
                         try {
-                            plcValue = toPlcValue(requestPdu, responsePdu, field.getDataType());
+                            plcValue = toPlcValue(requestPdu, responsePdu, field);
                             responseCode = PlcResponseCode.OK;
                         } catch (ParseException e) {
                             // Add an error response code ...
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusExtendedRegister.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusExtendedRegister.java
index 40dda0f..bbd638a 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusExtendedRegister.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusExtendedRegister.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusExtendedRegister extends ModbusField {
+public class ModbusExtendedRegister extends ModbusFieldBase {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("extended-register:" + ModbusField.ADDRESS_PATTERN);
-    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("6" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
-    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("6x" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("extended-register:" + ModbusFieldBase.ADDRESS_PATTERN);
+    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("6" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("6x" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
 
     protected static final int REGISTER_MAXADDRESS = 655359999;
 
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusField.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusField.java
index 9b3a6be..6789670 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusField.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusField.java
@@ -18,31 +18,12 @@
  */
 package org.apache.plc4x.java.modbus.base.field;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
-import org.apache.plc4x.java.modbus.readwrite.*;
-import org.apache.plc4x.java.spi.generation.SerializationException;
-import org.apache.plc4x.java.spi.generation.WriteBuffer;
 import org.apache.plc4x.java.spi.utils.Serializable;
 
-import java.nio.charset.StandardCharsets;
-import java.util.Objects;
-import java.util.regex.Pattern;
-
 public abstract class ModbusField implements PlcField, Serializable {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?<address>\\d+)(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
-    public static final Pattern FIXED_DIGIT_MODBUS_PATTERN = Pattern.compile("(?<address>\\d{4,5})?(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
-
-    protected static final int PROTOCOL_ADDRESS_OFFSET = 1;
-
-    private final int address;
-
-    private final int quantity;
-
-    private final ModbusDataType dataType;
-
     public static ModbusField of(String addressString) {
         if (ModbusFieldCoil.matches(addressString)) {
             return ModbusFieldCoil.of(addressString);
@@ -62,80 +43,4 @@
         throw new PlcInvalidFieldException("Unable to parse address: " + addressString);
     }
 
-    protected ModbusField(int address, Integer quantity, ModbusDataType dataType) {
-        this.address = address;
-        if ((this.address + PROTOCOL_ADDRESS_OFFSET) <= 0) {
-            throw new IllegalArgumentException("address must be greater than zero. Was " + (this.address + PROTOCOL_ADDRESS_OFFSET));
-        }
-        this.quantity = quantity != null ? quantity : 1;
-        if (this.quantity <= 0) {
-            throw new IllegalArgumentException("quantity must be greater than zero. Was " + this.quantity);
-        }
-        this.dataType = dataType != null ? dataType : ModbusDataType.INT;
-    }
-
-    public int getAddress() {
-        return address;
-    }
-
-    public int getNumberOfElements() {
-        return quantity;
-    }
-
-    public int getLengthBytes() {
-        return quantity * dataType.getDataTypeSize();
-    }
-
-    @JsonIgnore
-    public int getLengthWords() {
-        return (int) ((quantity * (float) dataType.getDataTypeSize()) / 2.0f);
-    }
-
-    public ModbusDataType getDataType() {
-        return dataType;
-    }
-
-    @Override
-    public String getPlcDataType() {
-        return dataType.name();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof ModbusField)) {
-            return false;
-        }
-        ModbusField that = (ModbusField) o;
-        return address == that.address;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(address);
-    }
-
-    @Override
-    public String toString() {
-        return "ModbusField{" +
-            "address=" + address +
-            "datatype=" + dataType +
-            "quantity=" + quantity +
-            '}';
-    }
-
-    @Override
-    public void serialize(WriteBuffer writeBuffer) throws SerializationException {
-        writeBuffer.pushContext(getClass().getSimpleName());
-
-        writeBuffer.writeUnsignedInt("address", 16, address);
-        writeBuffer.writeUnsignedInt("numberOfElements", 16, getNumberOfElements());
-        String dataType = getPlcDataType();
-        writeBuffer.writeString("dataType", dataType.getBytes(StandardCharsets.UTF_8).length * 8, StandardCharsets.UTF_8.name(), dataType);
-
-        writeBuffer.popContext(getClass().getSimpleName());
-    }
-
 }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldBase.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldBase.java
new file mode 100644
index 0000000..14576fa
--- /dev/null
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldBase.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.java.modbus.base.field;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.spi.generation.SerializationException;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+public abstract class ModbusFieldBase extends ModbusField {
+
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?<address>\\d+)(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
+    public static final Pattern FIXED_DIGIT_MODBUS_PATTERN = Pattern.compile("(?<address>\\d{4,5})?(:(?<datatype>[a-zA-Z_]+))?(\\[(?<quantity>\\d+)])?");
+
+    protected static final int PROTOCOL_ADDRESS_OFFSET = 1;
+
+    private final int address;
+
+    private final int quantity;
+
+    private final ModbusDataType dataType;
+
+    protected ModbusFieldBase(int address, Integer quantity, ModbusDataType dataType) {
+        this.address = address;
+        if ((this.address + PROTOCOL_ADDRESS_OFFSET) <= 0) {
+            throw new IllegalArgumentException("address must be greater than zero. Was " + (this.address + PROTOCOL_ADDRESS_OFFSET));
+        }
+        this.quantity = quantity != null ? quantity : 1;
+        if (this.quantity <= 0) {
+            throw new IllegalArgumentException("quantity must be greater than zero. Was " + this.quantity);
+        }
+        this.dataType = dataType != null ? dataType : ModbusDataType.INT;
+    }
+
+    public int getAddress() {
+        return address;
+    }
+
+    public int getNumberOfElements() {
+        return quantity;
+    }
+
+    public int getLengthBytes() {
+        return quantity * dataType.getDataTypeSize();
+    }
+
+    @JsonIgnore
+    public int getLengthWords() {
+        return (int) ((quantity * (float) dataType.getDataTypeSize()) / 2.0f);
+    }
+
+    public ModbusDataType getDataType() {
+        return dataType;
+    }
+
+    @Override
+    public String getPlcDataType() {
+        return dataType.name();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ModbusFieldBase)) {
+            return false;
+        }
+        ModbusFieldBase that = (ModbusFieldBase) o;
+        return address == that.address;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(address);
+    }
+
+    @Override
+    public String toString() {
+        return "ModbusField{" +
+            "address=" + address +
+            "datatype=" + dataType +
+            "quantity=" + quantity +
+            '}';
+    }
+
+    @Override
+    public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+        writeBuffer.pushContext(getClass().getSimpleName());
+
+        writeBuffer.writeUnsignedInt("address", 16, address);
+        writeBuffer.writeUnsignedInt("numberOfElements", 16, getNumberOfElements());
+        String dataType = getPlcDataType();
+        writeBuffer.writeString("dataType", dataType.getBytes(StandardCharsets.UTF_8).length * 8, StandardCharsets.UTF_8.name(), dataType);
+
+        writeBuffer.popContext(getClass().getSimpleName());
+    }
+
+}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldCoil.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldCoil.java
index 631f557..a128c79 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldCoil.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldCoil.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldCoil extends ModbusField {
+public class ModbusFieldCoil extends ModbusFieldBase {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("coil:" + ModbusField.ADDRESS_PATTERN);
-    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("0" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
-    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("0x" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("coil:" + ModbusFieldBase.ADDRESS_PATTERN);
+    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("0" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("0x" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
 
     protected static final int REGISTER_MAXADDRESS = 65535;
 
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldDiscreteInput.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldDiscreteInput.java
index bd365a6..3beb835 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldDiscreteInput.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldDiscreteInput.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldDiscreteInput extends ModbusField {
+public class ModbusFieldDiscreteInput extends ModbusFieldBase {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("discrete-input:" + ModbusField.ADDRESS_PATTERN);
-    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("1" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
-    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("1x" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("discrete-input:" + ModbusFieldBase.ADDRESS_PATTERN);
+    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("1" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("1x" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
 
     protected static final int REGISTER_MAX_ADDRESS = 65535;
 
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHandler.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHandler.java
index c62d3d0..21e6fb2 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHandler.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHandler.java
@@ -36,6 +36,8 @@
             return ModbusFieldCoil.of(fieldQuery);
         } else if (ModbusExtendedRegister.matches(fieldQuery)) {
             return ModbusExtendedRegister.of(fieldQuery);
+        } else if (ModbusIdentificationRegister.matches(fieldQuery)) {
+            return ModbusIdentificationRegister.of(fieldQuery);
         }
         throw new PlcInvalidFieldException(fieldQuery);
     }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHoldingRegister.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHoldingRegister.java
index 3872ffa..ab10830 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHoldingRegister.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldHoldingRegister.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldHoldingRegister extends ModbusField {
+public class ModbusFieldHoldingRegister extends ModbusFieldBase {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("holding-register:" + ModbusField.ADDRESS_PATTERN);
-    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("4" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
-    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("4x" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("holding-register:" + ModbusFieldBase.ADDRESS_PATTERN);
+    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("4" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("4x" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
 
     protected static final int REGISTER_MAXADDRESS = 65535;
 
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldInputRegister.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldInputRegister.java
index 6c26e27..d5d7bd5 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldInputRegister.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusFieldInputRegister.java
@@ -24,11 +24,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldInputRegister extends ModbusField {
+public class ModbusFieldInputRegister extends ModbusFieldBase {
 
-    public static final Pattern ADDRESS_PATTERN = Pattern.compile("input-register:" + ModbusField.ADDRESS_PATTERN);
-    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("3" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
-    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("3x" + ModbusField.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("input-register:" + ModbusFieldBase.ADDRESS_PATTERN);
+    public static final Pattern ADDRESS_SHORTER_PATTERN = Pattern.compile("3" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
+    public static final Pattern ADDRESS_SHORT_PATTERN = Pattern.compile("3x" + ModbusFieldBase.FIXED_DIGIT_MODBUS_PATTERN);
 
     protected static final int REGISTER_MAXADDRESS = 65535;
 
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusIdentificationRegister.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusIdentificationRegister.java
new file mode 100644
index 0000000..0f40a84
--- /dev/null
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/field/ModbusIdentificationRegister.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.java.modbus.base.field;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.modbus.readwrite.ModbusDeviceInformationLevel;
+import org.apache.plc4x.java.spi.generation.SerializationException;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+public class ModbusIdentificationRegister extends ModbusField {
+
+    public static final String HEX = "0[xX][0-9a-fA-F]+";
+    public static final String LEVEL = "(?<level>\\d+|" + HEX + "|(?:BASIC|REGULAR|EXTENDED|INDIVIDUAL))";
+    public static final String OBJECT_ID = "(?<objectId>\\d+|" + HEX + ")";
+    public static final Pattern ADDRESS_PATTERN = Pattern.compile("identification:" + LEVEL + ":" + OBJECT_ID);
+
+    private final ModbusDeviceInformationLevel level;
+    private final short objectId;
+
+    protected ModbusIdentificationRegister(ModbusDeviceInformationLevel level, short objectId) {
+        this.level = level;
+        this.objectId = objectId;
+    }
+
+    public static boolean matches(String addressString) {
+        return ADDRESS_PATTERN.matcher(addressString).matches();
+    }
+
+    public static Matcher getMatcher(String addressString) {
+        Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
+        if (matcher.matches()) {
+          return matcher;
+        }
+
+        throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN);
+    }
+
+    public static ModbusIdentificationRegister of(String addressString) {
+        Matcher matcher = getMatcher(addressString);
+        String levelGroup = matcher.group("level");
+        String objectidGroup = matcher.group("objectId");
+
+        ModbusDeviceInformationLevel level = parseNumber(levelGroup)
+            .map(Integer::byteValue)
+            .map(ModbusDeviceInformationLevel::enumForValue)
+            .orElseGet(() -> ModbusDeviceInformationLevel.valueOf(levelGroup.toUpperCase()));
+
+        int objectId = parseNumber(objectidGroup)
+            .orElseThrow(() -> new IllegalArgumentException("Invalid field definition detected, unknown object id"));
+
+        return new ModbusIdentificationRegister(level, (short) objectId);
+    }
+
+    private static Optional<Integer> parseNumber(String value) {
+        if (value.matches("\\d+")) {
+            return Optional.of(Integer.parseInt(value));
+        } else if (value.matches(HEX)) {
+            return Optional.of(Integer.parseInt(value.substring(2), 16));
+        }
+        return Optional.empty();
+    }
+
+    public ModbusDeviceInformationLevel getLevel() {
+        return level;
+    }
+
+    public short getObjectId() {
+        return objectId;
+    }
+
+    @Override
+    public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+        writeBuffer.pushContext(getClass().getSimpleName());
+        writeBuffer.writeShort("level", 8, level.getValue());
+        writeBuffer.writeShort("objectId", 8, objectId);
+        writeBuffer.popContext(getClass().getSimpleName());
+    }
+}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java
index 1aa8fe1..2289061 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java
@@ -18,13 +18,15 @@
  */
 package org.apache.plc4x.java.modbus.base.protocol;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
-import org.apache.plc4x.java.modbus.tcp.config.ModbusTcpConfiguration;
 import org.apache.plc4x.java.modbus.base.field.ModbusField;
+import org.apache.plc4x.java.modbus.base.field.ModbusFieldBase;
+import org.apache.plc4x.java.modbus.base.field.ModbusIdentificationRegister;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldCoil;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldDiscreteInput;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldHoldingRegister;
@@ -33,16 +35,11 @@
 import org.apache.plc4x.java.modbus.readwrite.*;
 import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.Plc4xProtocolBase;
-import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.generation.*;
-import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
-import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
-import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
-import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
 import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.plc4x.java.spi.values.PlcBOOL;
+import org.apache.plc4x.java.spi.values.PlcByteArray;
 import org.apache.plc4x.java.spi.values.PlcList;
 
 import java.time.Duration;
@@ -51,8 +48,10 @@
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.plc4x.java.spi.values.PlcSINT;
+import org.apache.plc4x.java.spi.values.PlcStruct;
+import org.apache.plc4x.java.spi.values.PlcUSINT;
 
 public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProtocolBase<T> {
 
@@ -147,6 +146,11 @@
                 itemArray = Arrays.asList(group1, group2);
             }
             return new ModbusPDUReadFileRecordRequest(itemArray);
+        } else if (field instanceof ModbusIdentificationRegister) {
+            ModbusIdentificationRegister identification = (ModbusIdentificationRegister) field;
+            return new ModbusPDUReadDeviceIdentificationRequest(
+                identification.getLevel(), identification.getObjectId()
+            );
         }
         throw new PlcRuntimeException("Unsupported read field type " + field.getClass().getName());
     }
@@ -211,7 +215,44 @@
         throw new PlcRuntimeException("Unsupported write field type " + field.getClass().getName());
     }
 
-    protected PlcValue toPlcValue(ModbusPDU request, ModbusPDU response, ModbusDataType dataType) throws ParseException {
+    protected PlcValue toPlcValue(ModbusPDU request, ModbusPDU response, ModbusField field) throws ParseException {
+        if (field instanceof ModbusFieldBase) {
+            return toPlcValue(request, response, ((ModbusFieldBase) field).getDataType());
+        }
+        if (request instanceof ModbusPDUReadDeviceIdentificationRequest) {
+            if (!(response instanceof ModbusPDUReadDeviceIdentificationResponse)) {
+                throw new PlcRuntimeException("Unexpected response type. " +
+                    "Expected ModbusPDUReadDeviceIdentificationResponse, but got " + response.getClass().getName());
+            }
+
+            ModbusPDUReadDeviceIdentificationResponse rsp = (ModbusPDUReadDeviceIdentificationResponse) response;
+//            protected final ModbusDeviceInformationLevel level;
+//            protected final boolean individualAccess;
+//            protected final ModbusDeviceInformationConformityLevel conformityLevel;
+//            protected final ModbusDeviceInformationMoreFollows moreFollows;
+//            protected final short nextObjectId;
+//            protected final List<ModbusDeviceInformationObject> objects;
+            Map<String, PlcValue> data = new LinkedHashMap<>();
+            data.put("level", new PlcUSINT(rsp.getLevel().getValue()));
+            data.put("individualAccess", new PlcBOOL(rsp.getIndividualAccess()));
+            data.put("conformityLevel", new PlcUSINT(rsp.getConformityLevel().getValue()));
+            data.put("moreFollows", new PlcBOOL(rsp.getMoreFollows() == ModbusDeviceInformationMoreFollows.MORE_OBJECTS_AVAILABLE));
+            data.put("nextObjectId", new PlcUSINT(rsp.getNextObjectId()));
+            List objectList = new ArrayList<>();
+            for (ModbusDeviceInformationObject object : rsp.getObjects()) {
+                Map<String, PlcValue> objectMap = new LinkedHashMap<>();
+                objectMap.put("objectId", new PlcUSINT(object.getObjectId()));
+                objectMap.put("data", new PlcByteArray(object.getData()));
+                objectList.add(new PlcStruct(objectMap));
+            }
+            data.put("objects", new PlcList(objectList));
+            return new PlcStruct(data);
+
+        }
+        return null;
+    }
+
+    private PlcValue toPlcValue(ModbusPDU request, ModbusPDU response, ModbusDataType dataType) throws ParseException {
         short fieldDataTypeSize = dataType.getDataTypeSize();
 
         if (request instanceof ModbusPDUReadDiscreteInputsRequest) {
@@ -285,13 +326,13 @@
     }
 
     protected byte[] fromPlcValue(PlcField field, PlcValue plcValue) {
-        ModbusDataType fieldDataType = ((ModbusField) field).getDataType();
+        ModbusDataType fieldDataType = ((ModbusFieldBase) field).getDataType();
         try {
             if (plcValue instanceof PlcList) {
                 WriteBufferByteBased writeBuffer = new WriteBufferByteBased(DataItem.getLengthInBytes(plcValue, fieldDataType, plcValue.getLength()));
                 DataItem.staticSerialize(writeBuffer, plcValue, fieldDataType, plcValue.getLength(), ByteOrder.BIG_ENDIAN);
                 byte[] data = writeBuffer.getData();
-                if (((ModbusField) field).getDataType() == ModbusDataType.BOOL) {
+                if (((ModbusFieldBase) field).getDataType() == ModbusDataType.BOOL) {
                     //Reverse Bits in each byte as
                     //they should be ordered like this: 8 7 6 5 4 3 2 1 | 0 0 0 0 0 0 0 9
                     byte[] bytes = new byte[data.length];
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
index 09accd2..d191198 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
@@ -26,11 +26,10 @@
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
-import org.apache.plc4x.java.modbus.base.field.ModbusField;
+import org.apache.plc4x.java.modbus.base.field.ModbusFieldBase;
 import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
 import org.apache.plc4x.java.modbus.readwrite.*;
 import org.apache.plc4x.java.modbus.rtu.config.ModbusRtuConfiguration;
-import org.apache.plc4x.java.modbus.tcp.config.ModbusTcpConfiguration;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
@@ -74,7 +73,7 @@
         // Example for sending a request ...
         if (request.getFieldNames().size() == 1) {
             String fieldName = request.getFieldNames().iterator().next();
-            ModbusField field = (ModbusField) request.getField(fieldName);
+            ModbusFieldBase field = (ModbusFieldBase) request.getField(fieldName);
             final ModbusPDU requestPdu = getReadRequestPdu(field);
 
             ModbusRtuADU modbusRtuADU = new ModbusRtuADU(unitIdentifier, requestPdu, false);
@@ -94,7 +93,7 @@
                         responseCode = getErrorCode(errorResponse);
                     } else {
                         try {
-                            plcValue = toPlcValue(requestPdu, responsePdu, field.getDataType());
+                            plcValue = toPlcValue(requestPdu, responsePdu, field);
                             responseCode = PlcResponseCode.OK;
                         } catch (ParseException e) {
                             // Add an error response code ...
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
index e4aad24..f020f9c 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
@@ -27,9 +27,9 @@
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.modbus.base.field.ModbusField;
+import org.apache.plc4x.java.modbus.base.field.ModbusFieldBase;
 import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
 import org.apache.plc4x.java.modbus.readwrite.*;
-import org.apache.plc4x.java.modbus.rtu.config.ModbusRtuConfiguration;
 import org.apache.plc4x.java.modbus.tcp.config.ModbusTcpConfiguration;
 import org.apache.plc4x.java.spi.configuration.HasConfiguration;
 import org.apache.plc4x.java.spi.generation.ParseException;
@@ -101,7 +101,7 @@
                         responseCode = getErrorCode(errorResponse);
                     } else {
                         try {
-                            plcValue = toPlcValue(requestPdu, responsePdu, field.getDataType());
+                            plcValue = toPlcValue(requestPdu, responsePdu, field);
                             responseCode = PlcResponseCode.OK;
                         } catch (ParseException e) {
                             // Add an error response code ...
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusFieldTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusFieldTest.java
index 90231b0..fcf1dac 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusFieldTest.java
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ModbusFieldTest.java
@@ -19,10 +19,12 @@
 package org.apache.plc4x.java.modbus;
 
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldHoldingRegister;
+import org.apache.plc4x.java.modbus.base.field.ModbusIdentificationRegister;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldInputRegister;
 import org.apache.plc4x.java.modbus.base.field.ModbusExtendedRegister;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldDiscreteInput;
 import org.apache.plc4x.java.modbus.base.field.ModbusFieldCoil;
+import org.apache.plc4x.java.modbus.readwrite.ModbusDeviceInformationLevel;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -68,4 +70,21 @@
         }
     }
 
+    @Test
+    public void testIdentificationField() {
+        ModbusDeviceInformationLevel level = ModbusDeviceInformationLevel.EXTENDED;
+        short objectId = 10;
+
+        ModbusIdentificationRegister identification = ModbusIdentificationRegister.of("identification:EXTENDED:10");
+        Assertions.assertEquals(level, identification.getLevel());
+        Assertions.assertEquals(objectId, identification.getObjectId());
+
+        identification = ModbusIdentificationRegister.of("identification:0x03:10");
+        Assertions.assertEquals(level, identification.getLevel());
+        Assertions.assertEquals(objectId, identification.getObjectId());
+
+        identification = ModbusIdentificationRegister.of("identification:0x3:0xA");
+        Assertions.assertEquals(level, identification.getLevel());
+        Assertions.assertEquals(objectId, identification.getObjectId());
+    }
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
index f587ced..099b03b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcStruct.java
@@ -96,7 +96,7 @@
                 throw new PlcRuntimeException("Error serializing. List item doesn't implement XmlSerializable");
             }
             ((Serializable) fieldValue).serialize(writeBuffer);
-            writeBuffer.pushContext(fieldName);
+            writeBuffer.popContext(fieldName);
         }
         writeBuffer.popContext("PlcStruct");
     }
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/tcp/DriverTestsuite.xml b/protocols/modbus/src/test/resources/protocols/modbus/tcp/DriverTestsuite.xml
index 309e271..d83e1b2 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/tcp/DriverTestsuite.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/tcp/DriverTestsuite.xml
@@ -532,4 +532,153 @@
     </steps>
   </testcase>
 
+
+  <testcase>
+    <name>Identification request</name>
+    <steps>
+      <api-request name="Receive Identification request">
+        <TestReadRequest>
+          <fields>
+            <field className="org.apache.plc4x.test.driver.internal.api.TestValueField">
+              <name>hurz</name>
+              <address>identification:BASIC:1</address>
+            </field>
+          </fields>
+        </TestReadRequest>
+      </api-request>
+      <outgoing-plc-message name="Send Modbus Input-Register Write Request">
+        <parser-arguments>
+          <driverType>MODBUS_TCP</driverType>
+          <response>false</response>
+        </parser-arguments>
+        <ModbusADU>
+          <ModbusTcpADU>
+            <transactionIdentifier dataType="uint" bitLength="16">1</transactionIdentifier>
+            <protocolIdentifier dataType="uint" bitLength="16">0</protocolIdentifier>
+            <length dataType="uint" bitLength="16">5</length>
+            <unitIdentifier dataType="uint" bitLength="8">1</unitIdentifier>
+            <pdu>
+              <ModbusPDU>
+                <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+                <functionFlag dataType="uint" bitLength="7">43</functionFlag>
+                <ModbusPDUReadDeviceIdentificationRequest>
+                  <meiType dataType="uint" bitLength="8">14</meiType>
+                  <level>
+                    <ModbusDeviceInformationLevel dataType="uint" bitLength="8" stringRepresentation="BASIC">1</ModbusDeviceInformationLevel>
+                  </level>
+                  <objectId dataType="uint" bitLength="8">1</objectId>
+                </ModbusPDUReadDeviceIdentificationRequest>
+              </ModbusPDU>
+            </pdu>
+          </ModbusTcpADU>
+        </ModbusADU>
+      </outgoing-plc-message>
+      <incoming-plc-message name="Receive Modbus Identification Response">
+        <parser-arguments>
+          <driverType>MODBUS_TCP</driverType>
+          <response>true</response>
+        </parser-arguments>
+        <ModbusADU>
+          <ModbusTcpADU>
+            <transactionIdentifier dataType="uint" bitLength="16">1</transactionIdentifier>
+            <protocolIdentifier dataType="uint" bitLength="16">0</protocolIdentifier>
+            <length dataType="uint" bitLength="16">15</length>
+            <unitIdentifier dataType="uint" bitLength="8">1</unitIdentifier>
+            <pdu>
+              <ModbusPDU>
+                <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+                <functionFlag dataType="uint" bitLength="7">43</functionFlag>
+                <ModbusPDUReadDeviceIdentificationResponse>
+                  <meiType dataType="uint" bitLength="8">14</meiType>
+                  <level>
+                    <ModbusDeviceInformationLevel dataType="uint" bitLength="8" stringRepresentation="BASIC">1</ModbusDeviceInformationLevel>
+                  </level>
+                  <individualAccess dataType="bit" bitLength="1">false</individualAccess>
+                  <conformityLevel>
+                    <ModbusDeviceInformationConformityLevel dataType="uint" bitLength="7" stringRepresentation="EXTENDED_STREAM_ONLY">3</ModbusDeviceInformationConformityLevel>
+                  </conformityLevel>
+                  <moreFollows>
+                    <ModbusDeviceInformationMoreFollows dataType="uint" bitLength="8" stringRepresentation="NO_MORE_OBJECTS_AVAILABLE">0</ModbusDeviceInformationMoreFollows>
+                  </moreFollows>
+                  <nextObjectId dataType="uint" bitLength="8">135</nextObjectId>
+                  <numberOfObjects dataType="uint" bitLength="8">2</numberOfObjects>
+                  <objects isList="true">
+                    <ModbusDeviceInformationObject>
+                      <objectId dataType="uint" bitLength="8">135</objectId>
+                      <objectLength dataType="uint" bitLength="8">1</objectLength>
+                      <data dataType="byte" bitLength="8">0x01</data>
+                    </ModbusDeviceInformationObject>
+                    <ModbusDeviceInformationObject>
+                      <objectId dataType="uint" bitLength="8">136</objectId>
+                      <objectLength dataType="uint" bitLength="8">2</objectLength>
+                      <data dataType="byte" bitLength="16">0x313d</data>
+                    </ModbusDeviceInformationObject>
+                  </objects>
+                </ModbusPDUReadDeviceIdentificationResponse>
+              </ModbusPDU>
+            </pdu>
+          </ModbusTcpADU>
+        </ModbusADU>
+      </incoming-plc-message>
+      <api-response name="Report Identification Response to application">
+        <PlcReadResponse>
+          <PlcReadRequest>
+            <fields>
+              <hurz>
+                <ModbusIdentificationRegister>
+                  <level dataType="int" bitLength="8">1</level>
+                  <objectId dataType="int" bitLength="8">1</objectId>
+                </ModbusIdentificationRegister>
+              </hurz>
+            </fields>
+          </PlcReadRequest>
+          <values>
+            <hurz>
+              <ResponseItem>
+                <result dataType="string" bitLength="16" encoding="UTF-8">OK</result>
+                <PlcStruct>
+                  <level>
+                    <PlcUSINT dataType="int" bitLength="8">1</PlcUSINT>
+                  </level>
+                  <individualAccess>
+                    <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+                  </individualAccess>
+                  <conformityLevel>
+                    <PlcUSINT dataType="int" bitLength="8">3</PlcUSINT>
+                  </conformityLevel>
+                  <moreFollows>
+                    <PlcBOOL dataType="bit" bitLength="1">false</PlcBOOL>
+                  </moreFollows>
+                  <nextObjectId>
+                    <PlcUSINT dataType="int" bitLength="8">135</PlcUSINT>
+                  </nextObjectId>
+                  <objects>
+                    <PlcList>
+                      <PlcStruct>
+                        <objectId>
+                          <PlcUSINT dataType="int" bitLength="8">135</PlcUSINT>
+                        </objectId>
+                        <data>
+                          <PlcByteArray dataType="byte" bitLength="8">0x01</PlcByteArray>
+                        </data>
+                      </PlcStruct>
+                      <PlcStruct>
+                        <objectId>
+                          <PlcUSINT dataType="int" bitLength="8">136</PlcUSINT>
+                        </objectId>
+                        <data>
+                          <PlcByteArray dataType="byte" bitLength="16">0x313d</PlcByteArray>
+                        </data>
+                      </PlcStruct>
+                    </PlcList>
+                  </objects>
+                </PlcStruct>
+              </ResponseItem>
+            </hurz>
+          </values>
+        </PlcReadResponse>
+      </api-response>
+    </steps>
+  </testcase>
+
 </test:driver-testsuite>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/tcp/ParserSerializerTestsuite.xml b/protocols/modbus/src/test/resources/protocols/modbus/tcp/ParserSerializerTestsuite.xml
index 9463e1c..bd5135c 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/tcp/ParserSerializerTestsuite.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/tcp/ParserSerializerTestsuite.xml
@@ -88,6 +88,96 @@
   </testcase>
 
   <testcase>
+    <name>Device identification request</name>
+    <raw>
+      000100000005012b0e0387
+    </raw>
+    <root-type>ModbusADU</root-type>
+    <parser-arguments>
+      <driverType>MODBUS_TCP</driverType>
+      <response>false</response>
+    </parser-arguments>
+    <xml>
+      <ModbusADU>
+        <ModbusTcpADU>
+          <transactionIdentifier dataType="uint" bitLength="16">1</transactionIdentifier>
+          <protocolIdentifier dataType="uint" bitLength="16">0</protocolIdentifier>
+          <length dataType="uint" bitLength="16">5</length>
+          <unitIdentifier dataType="uint" bitLength="8">1</unitIdentifier>
+          <pdu>
+            <ModbusPDU>
+              <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+              <functionFlag dataType="uint" bitLength="7">43</functionFlag>
+              <ModbusPDUReadDeviceIdentificationRequest>
+                <meiType dataType="uint" bitLength="8">14</meiType>
+                <level>
+                  <ModbusDeviceInformationLevel dataType="uint" bitLength="8" stringRepresentation="EXTENDED">3</ModbusDeviceInformationLevel>
+                </level>
+                <objectId dataType="uint" bitLength="8">135</objectId>
+              </ModbusPDUReadDeviceIdentificationRequest>
+            </ModbusPDU>
+          </pdu>
+        </ModbusTcpADU>
+      </ModbusADU>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Device identification response</name>
+    <raw>
+      00010000000f012b0e03030087028701018802313d
+    </raw>
+    <root-type>ModbusADU</root-type>
+    <parser-arguments>
+      <driverType>MODBUS_TCP</driverType>
+      <response>true</response>
+    </parser-arguments>
+    <xml>
+      <ModbusADU>
+        <ModbusTcpADU>
+          <transactionIdentifier dataType="uint" bitLength="16">1</transactionIdentifier>
+          <protocolIdentifier dataType="uint" bitLength="16">0</protocolIdentifier>
+          <length dataType="uint" bitLength="16">15</length>
+          <unitIdentifier dataType="uint" bitLength="8">1</unitIdentifier>
+          <pdu>
+            <ModbusPDU>
+              <errorFlag dataType="bit" bitLength="1">false</errorFlag>
+              <functionFlag dataType="uint" bitLength="7">43</functionFlag>
+              <ModbusPDUReadDeviceIdentificationResponse>
+                <meiType dataType="uint" bitLength="8">14</meiType>
+                <level>
+                  <ModbusDeviceInformationLevel dataType="uint" bitLength="8" stringRepresentation="EXTENDED">3</ModbusDeviceInformationLevel>
+                </level>
+                <individualAccess dataType="bit" bitLength="1">false</individualAccess>
+                <conformityLevel>
+                  <ModbusDeviceInformationConformityLevel dataType="uint" bitLength="7" stringRepresentation="EXTENDED_STREAM_ONLY">3</ModbusDeviceInformationConformityLevel>
+                </conformityLevel>
+                <moreFollows>
+                  <ModbusDeviceInformationMoreFollows dataType="uint" bitLength="8" stringRepresentation="NO_MORE_OBJECTS_AVAILABLE">0</ModbusDeviceInformationMoreFollows>
+                </moreFollows>
+                <nextObjectId dataType="uint" bitLength="8">135</nextObjectId>
+                <numberOfObjects dataType="uint" bitLength="8">2</numberOfObjects>
+                <objects isList="true">
+                  <ModbusDeviceInformationObject>
+                    <objectId dataType="uint" bitLength="8">135</objectId>
+                    <objectLength dataType="uint" bitLength="8">1</objectLength>
+                    <data dataType="byte" bitLength="8">0x01</data>
+                  </ModbusDeviceInformationObject>
+                  <ModbusDeviceInformationObject>
+                    <objectId dataType="uint" bitLength="8">136</objectId>
+                    <objectLength dataType="uint" bitLength="8">2</objectLength>
+                    <data dataType="byte" bitLength="16">0x313d</data>
+                  </ModbusDeviceInformationObject>
+                </objects>
+              </ModbusPDUReadDeviceIdentificationResponse>
+            </ModbusPDU>
+          </pdu>
+        </ModbusTcpADU>
+      </ModbusADU>
+    </xml>
+  </testcase>
+
+  <testcase>
     <name>Read Extended Registers Request Split File Record</name>
     <raw>000a0000001101140e060003270e000206000400000008</raw>
     <root-type>ModbusADU</root-type>