You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/01/19 20:35:05 UTC

[plc4x] branch develop updated: - Continued working on the Modbus driver

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new e22a83c  - Continued working on the Modbus driver
e22a83c is described below

commit e22a83cb95b3028e1f0e7402b4fc674f6d24d5a3
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sun Jan 19 21:34:57 2020 +0100

    - Continued working on the Modbus driver
---
 .../main/resources/protocols/modbus/modbus.mspec   | 98 +++++++++++-----------
 .../java/modbus/config/ModbusConfiguration.java    | 26 ++++++
 ...teInputs.java => ModbusFieldDiscreteInput.java} |  9 +-
 .../java/modbus/field/ModbusFieldHandler.java      | 20 ++---
 ...isters.java => ModbusFieldHoldingRegister.java} |  9 +-
 ...egisters.java => ModbusFieldInputRegister.java} |  8 +-
 .../modbus/field/ModbusFieldMaskWriteRegister.java |  9 +-
 .../java/modbus/field/ModbusFieldRegister.java     |  1 +
 .../java/modbus/protocol/ModbusProtocolLogic.java  | 83 ++++++++++++++++--
 .../test/resources/testsuite/ModbusTestsuite.xml   | 11 +--
 10 files changed, 186 insertions(+), 88 deletions(-)

diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index cb3d44c..6347dda 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -33,13 +33,13 @@
 
     // The length field is a byte count of the following fields, including the Unit Identifier and
     // data fields.
-    [simple         uint 16     'length']
+    [implicit       uint 16     'length'                'pdu.lengthInBytes + 1']
 
     // This field is used for intra-system routing purpose. It is typically used to communicate to
     // a MODBUS+ or a MODBUS serial line slave through a gateway between an Ethernet TCP-IP network
     // and a MODBUS serial line. This field is set by the MODBUS Client in the request and must be
     // returned with the same value in the response by the server.
-    [simple         uint 8      'unitItendifier']
+    [simple         uint 8      'unitIdentifier']
 
     // The actual modbus payload
     [simple         ModbusPDU   'pdu' ['response']]
@@ -59,89 +59,89 @@
     [implicit       uint 7      'function'  'DISCRIMINATOR_VALUES[1]']
     [implicit       bit         'error'     'DISCRIMINATOR_VALUES[0]']
     [typeSwitch 'error','function','response'
-        ['true'                     ModbusPduError
+        ['true'                     ModbusPDUError
             [simple     uint 8      'exceptionCode']
         ]
 
         // Bit Access
-        ['false','0x02','false'     ModbusPduReadDiscreteInputsRequest
+        ['false','0x02','false'     ModbusPDUReadDiscreteInputsRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
-        ['false','0x02','true'      ModbusPduReadDiscreteInputsResponse
+        ['false','0x02','true'      ModbusPDUReadDiscreteInputsResponse
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x01','false'     ModbusPduReadCoilsRequest
+        ['false','0x01','false'     ModbusPDUReadCoilsRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
-        ['false','0x01','true'      ModbusPduReadCoilsResponse
+        ['false','0x01','true'      ModbusPDUReadCoilsResponse
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x05','false'     ModbusPduWriteSingleCoilRequest
+        ['false','0x05','false'     ModbusPDUWriteSingleCoilRequest
             [simple     uint 16     'address']
             [simple     uint 16     'value']
         ]
-        ['false','0x05','true'      ModbusPduWriteSingleCoilResponse
+        ['false','0x05','true'      ModbusPDUWriteSingleCoilResponse
             [simple     uint 16     'address']
             [simple     uint 16     'value']
         ]
 
-        ['false','0x0F','false'     ModbusPduWriteMultipleCoilsRequest
+        ['false','0x0F','false'     ModbusPDUWriteMultipleCoilsRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
-        ['false','0x0F','true'      ModbusPduWriteMultipleCoilsResponse
+        ['false','0x0F','true'      ModbusPDUWriteMultipleCoilsResponse
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
 
         // Uint 16 Access (short)
-        ['false','0x04','false'     ModbusPduReadInputRegistersRequest
+        ['false','0x04','false'     ModbusPDUReadInputRegistersRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
-        ['false','0x04','true'      ModbusPduReadInputRegistersResponse
+        ['false','0x04','true'      ModbusPDUReadInputRegistersResponse
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x03','false'     ModbusPduReadHoldingRegistersRequest
+        ['false','0x03','false'     ModbusPDUReadHoldingRegistersRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
-        ['false','0x03','true'      ModbusPduReadHoldingRegistersResponse
+        ['false','0x03','true'      ModbusPDUReadHoldingRegistersResponse
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x06','false'     ModbusPduWriteSingleRegisterRequest
+        ['false','0x06','false'     ModbusPDUWriteSingleRegisterRequest
             [simple     uint 16     'address']
             [simple     uint 16     'value']
         ]
-        ['false','0x06','true'      ModbusPduWriteSingleRegisterResponse
+        ['false','0x06','true'      ModbusPDUWriteSingleRegisterResponse
             [simple     uint 16     'address']
             [simple     uint 16     'value']
         ]
 
-        ['false','0x10','false'     ModbusPduWriteMultipleRegistersRequest
+        ['false','0x10','false'     ModbusPDUWriteMultipleRegistersRequest
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
-        ['false','0x10','true'      ModbusPduWriteMultipleRegistersResponse
+        ['false','0x10','true'      ModbusPDUWriteMultipleRegistersResponse
             [simple     uint 16     'startingAddress']
             [simple     uint 16     'quantity']
         ]
 
-        ['false','0x17','false'     ModbusPduReadWriteMultipleRegistersRequest
+        ['false','0x17','false'     ModbusPDUReadWriteMultipleRegistersRequest
             [simple     uint 16     'readStartingAddress']
             [simple     uint 16     'readQuantity']
             [simple     uint 16     'writeStartingAddress']
@@ -149,74 +149,74 @@
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
-        ['false','0x17','true'      ModbusPduReadWriteMultipleRegistersResponse
+        ['false','0x17','true'      ModbusPDUReadWriteMultipleRegistersResponse
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x16','false'     ModbusPduMaskWriteRegisterRequest
+        ['false','0x16','false'     ModbusPDUMaskWriteRegisterRequest
             [simple     uint 16     'referenceAddress']
             [simple     uint 16     'andMask']
             [simple     uint 16     'orMask']
         ]
-        ['false','0x16','true'      ModbusPduMaskWriteRegisterResponse
+        ['false','0x16','true'      ModbusPDUMaskWriteRegisterResponse
             [simple     uint 16     'referenceAddress']
             [simple     uint 16     'andMask']
             [simple     uint 16     'orMask']
         ]
 
-        ['false','0x18','false'     ModbusPduReadFifoQueueRequest
+        ['false','0x18','false'     ModbusPDUReadFifoQueueRequest
             [simple     uint 16     'fifoPointerAddress']
         ]
-        ['false','0x18','true'      ModbusPduReadFifoQueueResponse
+        ['false','0x18','true'      ModbusPDUReadFifoQueueResponse
             [implicit   uint 16     'byteCount'     '(COUNT(fifoValue) * 2) + 2']
             [implicit   uint 16     'fifoCount'     '(COUNT(fifoValue) * 2) / 2']
             [array      uint 16     'fifoValue'     count   'fifoCount']
         ]
 
         // File Record Access
-        ['false','0x14','false'     ModbusPduReadFileRecordRequest
+        ['false','0x14','false'     ModbusPDUReadFileRecordRequest
             [implicit   uint 8      'byteCount'                 'ARRAY_SIZE_IN_BYTES(items)']
-            [array      ModbusPduReadFileRecordRequestItem      'items' length 'byteCount']
+            [array      ModbusPDUReadFileRecordRequestItem      'items' length 'byteCount']
         ]
-        ['false','0x14','true'      ModbusPduReadFileRecordResponse
+        ['false','0x14','true'      ModbusPDUReadFileRecordResponse
             [implicit   uint 8      'byteCount'                 'ARRAY_SIZE_IN_BYTES(items)']
-            [array      ModbusPduReadFileRecordResponseItem     'items' length 'byteCount']
+            [array      ModbusPDUReadFileRecordResponseItem     'items' length 'byteCount']
         ]
 
-        ['false','0x15','false'     ModbusPduWriteFileRecordRequest
+        ['false','0x15','false'     ModbusPDUWriteFileRecordRequest
             [implicit   uint 8      'byteCount'                 'ARRAY_SIZE_IN_BYTES(items)']
-            [array      ModbusPduWriteFileRecordRequestItem     'items' length 'byteCount']
+            [array      ModbusPDUWriteFileRecordRequestItem     'items' length 'byteCount']
         ]
-        ['false','0x15','true'      ModbusPduWriteFileRecordResponse
+        ['false','0x15','true'      ModbusPDUWriteFileRecordResponse
             [implicit   uint 8      'byteCount'                 'ARRAY_SIZE_IN_BYTES(items)']
-            [array      ModbusPduWriteFileRecordResponseItem    'items' length 'byteCount']
+            [array      ModbusPDUWriteFileRecordResponseItem    'items' length 'byteCount']
         ]
 
         // Diagnostics (Serial Line Only)
-        ['false','0x07','false'     ModbusPduReadExceptionStatusRequest
+        ['false','0x07','false'     ModbusPDUReadExceptionStatusRequest
         ]
-        ['false','0x07','true'      ModbusPduReadExceptionStatusResponse
+        ['false','0x07','true'      ModbusPDUReadExceptionStatusResponse
             [simple     uint 8      'value']
         ]
 
-        ['false','0x08','false'     ModbusPduDiagnosticRequest
+        ['false','0x08','false'     ModbusPDUDiagnosticRequest
             // TODO: Implement the sub-request discriminated type [simple uint 8  'subfunction']
         ]
-        ['false','0x08','true'      ModbusPduDiagnosticResponse
+        ['false','0x08','true'      ModbusPDUDiagnosticResponse
             // TODO: Implement the sub-request discriminated type [simple uint 8  'subfunction']
         ]
 
-        ['false','0x0B','false'     ModbusPduGetComEventCounterRequest
+        ['false','0x0B','false'     ModbusPDUGetComEventCounterRequest
         ]
-        ['false','0x0B','true'      ModbusPduGetComEventCounterResponse
+        ['false','0x0B','true'      ModbusPDUGetComEventCounterResponse
             [simple     uint 16     'status']
             [simple     uint 16     'eventCount']
         ]
 
-        ['false','0x0C','false'     ModbusPduGetComEventLogRequest
+        ['false','0x0C','false'     ModbusPDUGetComEventLogRequest
         ]
-        ['false','0x0C','true'      ModbusPduGetComEventLogResponse
+        ['false','0x0C','true'      ModbusPDUGetComEventLogResponse
             [implicit   uint 8      'byteCount'    'COUNT(events) + 6']
             [simple     uint 16     'status']
             [simple     uint 16     'eventCount']
@@ -224,35 +224,35 @@
             [array      int 8       'events'       count   'byteCount - 6']
         ]
 
-        ['false','0x11','false'     ModbusPduReportServerIdRequest
+        ['false','0x11','false'     ModbusPDUReportServerIdRequest
         ]
-        ['false','0x11','true'      ModbusPduReportServerIdResponse
+        ['false','0x11','true'      ModbusPDUReportServerIdResponse
             // TODO: This is not specified very well in the spec ... investigate.
             [implicit   uint 8      'byteCount'     'COUNT(value)']
             [array      int 8       'value'         count   'byteCount']
         ]
 
-        ['false','0x2B','false'     ModbusPduReadDeviceIdentificationRequest
+        ['false','0x2B','false'     ModbusPDUReadDeviceIdentificationRequest
         ]
-        ['false','0x2B','true'      ModbusPduReadDeviceIdentificationResponse
+        ['false','0x2B','true'      ModbusPDUReadDeviceIdentificationResponse
         ]
     ]
 ]
 
-[type 'ModbusPduReadFileRecordRequestItem'
+[type 'ModbusPDUReadFileRecordRequestItem'
     [simple     uint 8     'referenceType']
     [simple     uint 16    'fileNumber']
     [simple     uint 16    'recordNumber']
     [simple     uint 16    'recordLength']
 ]
 
-[type 'ModbusPduReadFileRecordResponseItem'
+[type 'ModbusPDUReadFileRecordResponseItem'
     [implicit   uint 8     'dataLength'     '(COUNT(data) * 2) + 1']
     [simple     uint 8     'referenceType']
     [array      uint 16    'data'           length  'dataLength - 1']
 ]
 
-[type 'ModbusPduWriteFileRecordRequestItem'
+[type 'ModbusPDUWriteFileRecordRequestItem'
     [simple     uint 8     'referenceType']
     [simple     uint 16    'fileNumber']
     [simple     uint 16    'recordNumber']
@@ -260,7 +260,7 @@
     [array      uint 16    'recordData'     length  'recordLength * 2']
 ]
 
-[type 'ModbusPduWriteFileRecordResponseItem'
+[type 'ModbusPDUWriteFileRecordResponseItem'
     [simple     uint 8     'referenceType']
     [simple     uint 16    'fileNumber']
     [simple     uint 16    'recordNumber']
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/config/ModbusConfiguration.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/config/ModbusConfiguration.java
index d8465ed..1cf97df 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/config/ModbusConfiguration.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/config/ModbusConfiguration.java
@@ -20,10 +20,36 @@ package org.apache.plc4x.java.modbus.config;
 
 import org.apache.plc4x.java.modbus.readwrite.ModbusConstants;
 import org.apache.plc4x.java.spi.configuration.Configuration;
+import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
+import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue;
 import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration;
 
 public class ModbusConfiguration implements Configuration, TcpTransportConfiguration {
 
+    @ConfigurationParameter("request-timeout")
+    @IntDefaultValue(10_000)
+    private int requestTimeout;
+
+    @ConfigurationParameter("unit-identifier")
+    @IntDefaultValue(1)
+    private int unitIdentifier;
+
+    public int getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    public void setRequestTimeout(int requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public int getUnitIdentifier() {
+        return unitIdentifier;
+    }
+
+    public void setUnitIdentifier(int unitIdentifier) {
+        this.unitIdentifier = unitIdentifier;
+    }
+
     @Override
     public int getDefaultPort() {
         return ModbusConstants.MODBUSTCPDEFAULTPORT;
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadDiscreteInputs.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
similarity index 83%
rename from sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadDiscreteInputs.java
rename to sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
index 49ffbe0..0ccdbf5 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadDiscreteInputs.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
@@ -23,15 +23,15 @@ import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldReadDiscreteInputs extends ModbusField {
+public class ModbusFieldDiscreteInput extends ModbusField {
 
     public static final Pattern ADDRESS_PATTERN = Pattern.compile("readdiscreteinputs:" + ModbusField.ADDRESS_PATTERN);
 
-    public ModbusFieldReadDiscreteInputs(int address, Integer quantity) {
+    public ModbusFieldDiscreteInput(int address, Integer quantity) {
         super(address, quantity);
     }
 
-    public static ModbusFieldReadDiscreteInputs of(String addressString) throws PlcInvalidFieldException {
+    public static ModbusFieldDiscreteInput of(String addressString) throws PlcInvalidFieldException {
         Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
         if (!matcher.matches()) {
             throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN);
@@ -40,6 +40,7 @@ public class ModbusFieldReadDiscreteInputs extends ModbusField {
 
         String quantityString = matcher.group("quantity");
         Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null;
-        return new ModbusFieldReadDiscreteInputs(address, quantity);
+        return new ModbusFieldDiscreteInput(address, quantity);
     }
+
 }
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
index 6f5b9d9..1ea13a1 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
@@ -19,18 +19,10 @@ under the License.
 package org.apache.plc4x.java.modbus.field;
 
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
 
-import java.lang.reflect.InvocationTargetException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Arrays;
 import java.util.BitSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -41,12 +33,12 @@ public class ModbusFieldHandler extends DefaultPlcFieldHandler {
     public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
         if (ModbusFieldMaskWriteRegister.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
             return ModbusFieldMaskWriteRegister.of(fieldQuery);
-        } else if (ModbusFieldReadDiscreteInputs.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
-            return ModbusFieldReadDiscreteInputs.of(fieldQuery);
-        } else if (ModbusFieldReadHoldingRegisters.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
-            return ModbusFieldReadHoldingRegisters.of(fieldQuery);
-        } else if (ModbusFieldReadInputRegisters.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
-            return ModbusFieldReadInputRegisters.of(fieldQuery);
+        } else if (ModbusFieldDiscreteInput.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
+            return ModbusFieldDiscreteInput.of(fieldQuery);
+        } else if (ModbusFieldHoldingRegister.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
+            return ModbusFieldHoldingRegister.of(fieldQuery);
+        } else if (ModbusFieldInputRegister.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
+            return ModbusFieldInputRegister.of(fieldQuery);
         } else if (ModbusFieldCoil.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
             return ModbusFieldCoil.of(fieldQuery);
         } else if (ModbusFieldRegister.ADDRESS_PATTERN.matcher(fieldQuery).matches()) {
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadHoldingRegisters.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
similarity index 82%
rename from sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadHoldingRegisters.java
rename to sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
index f0fe335..7d2cba3 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadHoldingRegisters.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
@@ -23,15 +23,15 @@ import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldReadHoldingRegisters extends ModbusField {
+public class ModbusFieldHoldingRegister extends ModbusField {
 
     public static final Pattern ADDRESS_PATTERN = Pattern.compile("readholdingregisters:" + ModbusField.ADDRESS_PATTERN);
 
-    protected ModbusFieldReadHoldingRegisters(int address, Integer quantity) {
+    protected ModbusFieldHoldingRegister(int address, Integer quantity) {
         super(address, quantity);
     }
 
-    public static ModbusFieldReadHoldingRegisters of(String addressString) throws PlcInvalidFieldException {
+    public static ModbusFieldHoldingRegister of(String addressString) throws PlcInvalidFieldException {
         Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
         if (!matcher.matches()) {
             throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN);
@@ -40,6 +40,7 @@ public class ModbusFieldReadHoldingRegisters extends ModbusField {
 
         String quantityString = matcher.group("quantity");
         Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null;
-        return new ModbusFieldReadHoldingRegisters(address, quantity);
+        return new ModbusFieldHoldingRegister(address, quantity);
     }
+
 }
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadInputRegisters.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
similarity index 82%
rename from sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadInputRegisters.java
rename to sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
index b63685d..1185554 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldReadInputRegisters.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
@@ -23,15 +23,15 @@ import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ModbusFieldReadInputRegisters extends ModbusField {
+public class ModbusFieldInputRegister extends ModbusField {
 
     public static final Pattern ADDRESS_PATTERN = Pattern.compile("readinputregisters:" + ModbusField.ADDRESS_PATTERN);
 
-    protected ModbusFieldReadInputRegisters(int address, Integer quantity) {
+    protected ModbusFieldInputRegister(int address, Integer quantity) {
         super(address, quantity);
     }
 
-    public static ModbusFieldReadInputRegisters of(String addressString) throws PlcInvalidFieldException {
+    public static ModbusFieldInputRegister of(String addressString) throws PlcInvalidFieldException {
         Matcher matcher = ADDRESS_PATTERN.matcher(addressString);
         if (!matcher.matches()) {
             throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN);
@@ -40,6 +40,6 @@ public class ModbusFieldReadInputRegisters extends ModbusField {
 
         String quantityString = matcher.group("quantity");
         Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null;
-        return new ModbusFieldReadInputRegisters(address, quantity);
+        return new ModbusFieldInputRegister(address, quantity);
     }
 }
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
index 4f714e6..5ad9f09 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
@@ -24,6 +24,13 @@ import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+/**
+ * This is not really an address, but a different type of operation.
+ * Perhaps in the future we will use this in order to send optimized requests,
+ * but for now it shouldn't be used and is just implemented for the sake of
+ * completeness.
+ */
+@Deprecated
 public class ModbusFieldMaskWriteRegister extends ModbusField {
 
     public static final Pattern ADDRESS_PATTERN = Pattern.compile("maskwrite:" + ModbusField.ADDRESS_PATTERN + "/" + "(?<andMask>\\d+)/(?<orMask>\\d+)");
@@ -77,7 +84,6 @@ public class ModbusFieldMaskWriteRegister extends ModbusField {
 
     @Override
     public int hashCode() {
-
         return Objects.hash(super.hashCode(), andMask, orMask);
     }
 
@@ -88,4 +94,5 @@ public class ModbusFieldMaskWriteRegister extends ModbusField {
             ", orMask=" + orMask +
             "} " + super.toString();
     }
+
 }
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldRegister.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldRegister.java
index 6fe1bb4..10da1ee 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldRegister.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldRegister.java
@@ -43,4 +43,5 @@ public class ModbusFieldRegister extends ModbusField {
         Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null;
         return new ModbusFieldRegister(address, quantity);
     }
+
 }
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
index 01b2575..796c542 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
@@ -22,36 +22,109 @@ import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
+import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.modbus.config.ModbusConfiguration;
-import org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU;
+import org.apache.plc4x.java.modbus.field.ModbusFieldCoil;
+import org.apache.plc4x.java.modbus.field.ModbusFieldDiscreteInput;
+import org.apache.plc4x.java.modbus.field.ModbusFieldHoldingRegister;
+import org.apache.plc4x.java.modbus.field.ModbusFieldInputRegister;
+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.messages.DefaultPlcReadRequest;
+import org.apache.plc4x.java.spi.optimizer.RequestTransactionManager;
 
+import java.time.Duration;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class ModbusProtocolLogic  extends Plc4xProtocolBase<ModbusTcpADU> implements HasConfiguration<ModbusConfiguration> {
 
-    private ModbusConfiguration configuration;
+    private Duration requestTimeout;
+    private short unitIdentifier;
+    private RequestTransactionManager tm;
+    private AtomicInteger transactionIdentifierGenerator = new AtomicInteger(10);
 
     @Override
     public void setConfiguration(ModbusConfiguration configuration) {
-        this.configuration = configuration;
+        this.requestTimeout = Duration.ofMillis(configuration.getRequestTimeout());
+        this.unitIdentifier = (short) configuration.getUnitIdentifier();
+        this.tm = new RequestTransactionManager(1);
+        this.transactionIdentifierGenerator = new AtomicInteger(10);
     }
 
     @Override
     public void close(ConversationContext<ModbusTcpADU> context) {
-
+        // Nothing to do here ...
     }
 
     @Override
     public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
-        return super.read(readRequest);
+        CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
+        DefaultPlcReadRequest request = (DefaultPlcReadRequest) readRequest;
+
+        // 1. Sort all items by type:
+        //      - DiscreteInput     (read-only)     --> ModbusPduReadDiscreteInputsRequest
+        //      - Coil              (read-write)    --> ModbusPduReadCoilsRequest
+        //      - InputRegister     (read-only)     --> ModbusPduReadInputRegistersRequest
+        //      - HoldingRegister   (read-write)    --> ModbusPduReadHoldingRegistersRequest
+        //      - FifoQueue         (read-only)     --> ModbusPduReadFifoQueueRequest
+        //      - FileRecord        (read-write)    --> ModbusPduReadFileRecordRequest
+        // 2. Split up into multiple sub-requests
+
+        // Example for sending a request ...
+        // TODO: Break down multiple items into sub-futures that are acknowledged at the end
+        for (PlcField field : request.getFields()) {
+            ModbusPDU requestPdu = getRequestPdu(field);
+            int transactionIdentifier = transactionIdentifierGenerator.getAndIncrement();
+            ModbusTcpADU modbusTcpADU = new ModbusTcpADU(transactionIdentifier, unitIdentifier, requestPdu);
+            RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+            transaction.submit(() -> context.sendRequest(modbusTcpADU)
+                .expectResponse(ModbusTcpADU.class, requestTimeout)
+                .onTimeout(future::completeExceptionally)
+                .onError((p, e) -> future.completeExceptionally(e))
+                .check(p -> p.getTransactionIdentifier() == transactionIdentifier)
+                .unwrap(ModbusTcpADU::getPdu)
+                .handle(p -> {
+                    // TODO: Do something sensible with the response ...
+                    //future.complete(p);
+                    // Finish the request-transaction.
+                    transaction.endRequest();
+            }));
+        }
+        // TODO: Merge all the sub-futures to one big response.
+        return future;
     }
 
     @Override
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
+        // 1. Sort all items by type:
+        //      - DiscreteInput     (read-only)     --> Error
+        //      - Coil              (read-write)    --> ModbusPduWriteSingleCoilRequest / ModbusPduWriteMultipleCoilsRequest
+        //      - InputRegister     (read-only)     --> Error
+        //      - HoldingRegister   (read-write)    --> ModbusPduWriteSingleRegisterRequest / ModbusPduWriteMultipleRegistersRequest
+        //      - FifoQueue         (read-only)     --> Error
+        //      - FileRecord        (read-write)    --> ModbusPduWriteFileRecordRequest
+        // 2. Split up into multiple sub-requests
         return super.write(writeRequest);
     }
 
+    private ModbusPDU getRequestPdu(PlcField field) {
+        if(field instanceof ModbusFieldDiscreteInput) {
+            ModbusFieldDiscreteInput discreteInput = (ModbusFieldDiscreteInput) field;
+            return new ModbusPDUReadDiscreteInputsRequest(discreteInput.getAddress(), discreteInput.getQuantity());
+        } else if(field instanceof ModbusFieldCoil) {
+            ModbusFieldCoil coil = (ModbusFieldCoil) field;
+            return new ModbusPDUReadCoilsRequest(coil.getAddress(), coil.getQuantity());
+        } else if(field instanceof ModbusFieldInputRegister) {
+            ModbusFieldInputRegister inputRegister = (ModbusFieldInputRegister) field;
+            return new ModbusPDUReadInputRegistersRequest(inputRegister.getAddress(), inputRegister.getQuantity());
+        } else if(field instanceof ModbusFieldHoldingRegister) {
+            ModbusFieldHoldingRegister holdingRegister = (ModbusFieldHoldingRegister) field;
+            return new ModbusPDUReadHoldingRegistersRequest(holdingRegister.getAddress(), holdingRegister.getQuantity());
+        }
+        throw new RuntimeException("Unsupported field type " + field.getClass().getName());
+    }
+
 }
diff --git a/sandbox/test-java-modbus-driver/src/test/resources/testsuite/ModbusTestsuite.xml b/sandbox/test-java-modbus-driver/src/test/resources/testsuite/ModbusTestsuite.xml
index 9fccfc3..7befd30 100644
--- a/sandbox/test-java-modbus-driver/src/test/resources/testsuite/ModbusTestsuite.xml
+++ b/sandbox/test-java-modbus-driver/src/test/resources/testsuite/ModbusTestsuite.xml
@@ -31,9 +31,8 @@
     <xml>
       <ModbusTcpADU className="org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU">
         <transactionIdentifier>0</transactionIdentifier>
-        <length>6</length>
-        <unitItendifier>255</unitItendifier>
-        <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPduReadDiscreteInputsRequest">
+        <unitIdentifier>255</unitIdentifier>
+        <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUReadDiscreteInputsRequest">
           <startingAddress>2258</startingAddress>
           <quantity>2</quantity>
         </pdu>
@@ -51,9 +50,8 @@
     <xml>
       <ModbusTcpADU className="org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU">
         <transactionIdentifier>31998</transactionIdentifier>
-        <length>201</length>
-        <unitItendifier>255</unitItendifier>
-        <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPduReadDiscreteInputsResponse">
+        <unitIdentifier>255</unitIdentifier>
+        <pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUReadDiscreteInputsResponse">
           <value>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABAAAAAAAAAAAAAAAAAAAAdsAAAHWAABKOAAAAAAAAAAA
 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRhaW0AbgAAAAAAAAAAAAAAAAAAMDEAMAAAAAAAAAAAAAAA
@@ -63,5 +61,4 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</value>
     </xml>
   </testcase>
 
-
 </test:testsuite>
\ No newline at end of file