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>