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 2018/08/29 16:57:51 UTC

[incubator-plc4x] branch feature/api-redesign-chris-c updated: - Adjusted the camel integration - Continued work on the Edgent integration - Started implementing the api changes in driver base

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

cdutz pushed a commit to branch feature/api-redesign-chris-c
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/feature/api-redesign-chris-c by this push:
     new abbf96c  - Adjusted the camel integration - Continued work on the Edgent integration - Started implementing the api changes in driver base
abbf96c is described below

commit abbf96caa04b240ec26f6af2086c85fd2add98a2
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Aug 29 18:57:42 2018 +0200

    - Adjusted the camel integration
    - Continued work on the Edgent integration
    - Started implementing the api changes in driver base
---
 .../java/org/apache/plc4x/camel/Constants.java     |   3 +-
 .../java/org/apache/plc4x/camel/Plc4XConsumer.java |  64 ++--
 .../apache/plc4x/camel/Plc4XPollingConsumer.java   |  32 +-
 .../java/org/apache/plc4x/camel/Plc4XProducer.java |  21 +-
 .../plc4x/camel/ResponseItemTypeConverter.java     |  34 ---
 .../services/org/apache/camel/TypeConverter        |  19 --
 .../apache/plc4x/edgent/PlcConnectionAdapter.java  |   1 -
 .../plc4x/edgent/PlcConnectionAdapterTest.java     |  22 --
 .../apache/plc4x/edgent/mock/MockConnection.java   |  10 +
 .../plc4x/java/api/connection/PlcConnection.java   |  11 -
 .../plc4x/java/api/connection/PlcSubscriber.java   |   4 +-
 .../plc4x/java/api/messages/PlcFieldRequest.java   |   5 -
 .../plc4x/java/api/messages/PlcReadRequest.java    |   2 -
 .../java/api/messages/PlcSubscriptionEvent.java    |   2 +-
 .../java/api/messages/PlcSubscriptionRequest.java  |  36 +++
 .../java/api/messages/PlcSubscriptionResponse.java |   4 +
 .../api/messages/PlcUnsubscriptionRequest.java     |  29 +-
 .../plc4x/java/api/messages/PlcWriteRequest.java   |   6 +-
 .../base/connection/AbstractPlcConnection.java     |   2 +-
 .../java/base/connection/PlcFieldHandler.java}     |  18 +-
 .../java/base/messages/DefaultPlcReadRequest.java  |  83 ++++++
 .../java/base/messages/DefaultPlcReadResponse.java | 324 +++++++++++++++++++++
 .../java/base/messages/DefaultPlcWriteRequest.java | 180 ++++++++++++
 .../base/messages/DefaultPlcWriteResponse.java}    |  30 +-
 .../plc4x/java/base/connection/MockConnection.java |   5 -
 .../plc4x/java/base/util/Junit5Backport.java       |   1 +
 .../plc4x/java/s7/connection/S7PlcConnection.java  |  45 ++-
 .../org/apache/plc4x/java/s7/model/S7BitField.java |  58 ----
 .../plc4x/java/s7/model/S7DataBlockField.java      |  57 ----
 .../org/apache/plc4x/java/s7/model/S7Field.java    |  66 ++++-
 .../plc4x/java/s7/netty/Plc4XS7Protocol.java       |  13 +-
 .../org/apache/plc4x/java/s7/types/S7DataType.java |  37 +--
 .../java/s7/connection/S7PlcConnectionTests.java   |   2 -
 .../apache/plc4x/java/s7/model/S7FieldTests.java   |   5 +
 .../plc4x/java/s7/netty/Plc4XS7ProtocolTest.java   |   2 -
 35 files changed, 853 insertions(+), 380 deletions(-)

diff --git a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Constants.java b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Constants.java
index ca9dedd..eefde57 100644
--- a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Constants.java
+++ b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Constants.java
@@ -20,7 +20,8 @@ package org.apache.plc4x.camel;
 
 public class Constants {
 
-    public static final String ADDRESS_HEADER = "address";
+    public static final String FIELD_NAME_HEADER = "fieldName";
+    public static final String FIELD_QUERY_HEADER = "fieldQuery";
     
     private Constants() {
       throw new IllegalStateException("Utility class!");
diff --git a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XConsumer.java b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XConsumer.java
index 8ce7dcd..510690a 100644
--- a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XConsumer.java
+++ b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XConsumer.java
@@ -26,31 +26,26 @@ import org.apache.camel.util.AsyncProcessorConverterHelper;
 import org.apache.plc4x.java.api.connection.PlcConnection;
 import org.apache.plc4x.java.api.connection.PlcSubscriber;
 import org.apache.plc4x.java.api.exceptions.PlcException;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
-import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse;
-import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest;
-import org.apache.plc4x.java.api.messages.items.SubscriptionEventItem;
-import org.apache.plc4x.java.api.messages.items.SubscriptionRequestCyclicItem;
-import org.apache.plc4x.java.api.messages.items.SubscriptionResponseItem;
-import org.apache.plc4x.java.api.messages.items.UnsubscriptionRequestItem;
-import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.messages.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.List;
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-public class Plc4XConsumer extends ServiceSupport implements Consumer, java.util.function.Consumer<SubscriptionEventItem> {
+public class Plc4XConsumer extends ServiceSupport implements Consumer, java.util.function.Consumer<PlcSubscriptionEvent> {
     private static final Logger LOGGER = LoggerFactory.getLogger(Plc4XConsumer.class);
 
     private Plc4XEndpoint endpoint;
     private AsyncProcessor processor;
     private ExceptionHandler exceptionHandler;
     private PlcConnection plcConnection;
-    private PlcField field;
+    private String fieldQuery;
     private Class<?> dataType;
     private PlcSubscriptionResponse subscriptionResponse;
 
@@ -62,7 +57,7 @@ public class Plc4XConsumer extends ServiceSupport implements Consumer, java.util
         this.exceptionHandler = new LoggingExceptionHandler(endpoint.getCamelContext(), getClass());
         String plc4xURI = endpoint.getEndpointUri().replaceFirst("plc4x:/?/?", "");
         this.plcConnection = endpoint.getPlcDriverManager().getConnection(plc4xURI);
-        this.field = plcConnection.prepareField(endpoint.getAddress());
+        this.fieldQuery = endpoint.getAddress();
     }
 
     @Override
@@ -84,22 +79,29 @@ public class Plc4XConsumer extends ServiceSupport implements Consumer, java.util
     }
 
     @Override
-    protected void doStart() throws InterruptedException, ExecutionException, TimeoutException {
-        PlcSubscriptionRequest request = new PlcSubscriptionRequest();
-        @SuppressWarnings("unchecked")
-        SubscriptionRequestCyclicItem subscriptionRequestCyclicItem = new SubscriptionRequestCyclicItem(dataType, field, TimeUnit.SECONDS, 3, this);
-        request.addItem(subscriptionRequestCyclicItem);
+    protected void doStart() throws InterruptedException, ExecutionException, TimeoutException, PlcException {
+        PlcSubscriber plcSubscriber = plcConnection.getSubscriber().orElseThrow(
+            () -> new PlcException("Connection doesn't support subscriptions."));
+        // TODO: Is it correct to only support one field?
+        PlcSubscriptionRequest request = plcSubscriber.subscriptionRequestBuilder()
+            .addCyclicField("default", fieldQuery, Duration.of(3, ChronoUnit.SECONDS)).build();
         CompletableFuture<PlcSubscriptionResponse> subscriptionFuture = getSubscriber().subscribe(request);
         subscriptionResponse = subscriptionFuture.get(5, TimeUnit.SECONDS);
     }
 
     @Override
-    protected void doStop() {
-        PlcUnsubscriptionRequest request = new PlcUnsubscriptionRequest();
-        subscriptionResponse.getResponseItems().stream()
-            .map(SubscriptionResponseItem::getSubscriptionHandle)
-            .map(UnsubscriptionRequestItem::new)
-            .forEach(request::addItem);
+    protected void doStop() throws InterruptedException, ExecutionException, TimeoutException, PlcException {
+        PlcSubscriber plcSubscriber = plcConnection.getSubscriber().orElseThrow(
+            () -> new PlcException("Connection doesn't support subscriptions."));
+        PlcUnsubscriptionRequest.Builder builder = plcSubscriber.unsubscriptionRequestBuilder();
+        // For every field we subscribed for, now unsubscribe.
+        subscriptionResponse.getFieldNames().forEach(fieldName -> {
+            builder.addField(fieldName, subscriptionResponse.getSubscriptionHandle(fieldName));
+        });
+        PlcUnsubscriptionRequest request = builder.build();
+        CompletableFuture<PlcUnsubscriptionResponse> unsubscriptionFuture = plcSubscriber.unsubscribe(request);
+        PlcUnsubscriptionResponse unsubscriptionResponse = unsubscriptionFuture.get(5, TimeUnit.SECONDS);
+        // TODO: Handle the response ...
         try {
             plcConnection.close();
         } catch (Exception e) {
@@ -112,25 +114,25 @@ public class Plc4XConsumer extends ServiceSupport implements Consumer, java.util
     }
 
     @Override
-    public void accept(SubscriptionEventItem subscriptionEventItem) {
-        LOGGER.debug("Received {}", subscriptionEventItem);
+    public void accept(PlcSubscriptionEvent plcSubscriptionEvent) {
+        LOGGER.debug("Received {}", plcSubscriptionEvent);
         try {
             Exchange exchange = endpoint.createExchange();
-            exchange.getIn().setBody(unwrapIfSingle(subscriptionEventItem.getValues()));
+            exchange.getIn().setBody(unwrapIfSingle(plcSubscriptionEvent.getAllObjects("default")));
             processor.process(exchange);
         } catch (Exception e) {
             exceptionHandler.handleException(e);
         }
     }
 
-    private Object unwrapIfSingle(List list) {
-        if (list.isEmpty()) {
+    private Object unwrapIfSingle(Collection collection) {
+        if (collection.isEmpty()) {
             return null;
         }
-        if (list.size() == 1) {
-            return list.get(0);
+        if (collection.size() == 1) {
+            return collection.iterator().next();
         }
-        return list;
+        return collection;
     }
 
 }
diff --git a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XPollingConsumer.java b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XPollingConsumer.java
index 57be55e..cb4e548 100644
--- a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XPollingConsumer.java
+++ b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XPollingConsumer.java
@@ -29,11 +29,10 @@ import org.apache.plc4x.java.api.connection.PlcReader;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
-import org.apache.plc4x.java.api.model.PlcField;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.List;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -45,17 +44,18 @@ public class Plc4XPollingConsumer extends ServiceSupport implements PollingConsu
     private Plc4XEndpoint endpoint;
     private ExceptionHandler exceptionHandler;
     private PlcConnection plcConnection;
-    private PlcField field;
+    private PlcReader plcReader;
+    private PlcReadRequest readRequest;
     private Class dataType;
 
-
     public Plc4XPollingConsumer(Plc4XEndpoint endpoint) throws PlcException {
         this.endpoint = endpoint;
         this.dataType = endpoint.getDataType();
         this.exceptionHandler = new LoggingExceptionHandler(endpoint.getCamelContext(), getClass());
         String plc4xURI = endpoint.getEndpointUri().replaceFirst("plc4x:/?/?", "");
         this.plcConnection = endpoint.getPlcDriverManager().getConnection(plc4xURI);
-        this.field = plcConnection.prepareField(endpoint.getAddress());
+        this.plcReader = plcConnection.getReader().orElseThrow(() -> new PlcException("This connection doesn't support reading."));
+        readRequest = plcReader.readRequestBuilder().addItem("default", endpoint.getAddress()).build();
     }
 
     @Override
@@ -79,10 +79,10 @@ public class Plc4XPollingConsumer extends ServiceSupport implements PollingConsu
     @Override
     public Exchange receive() {
         Exchange exchange = endpoint.createExchange();
-        CompletableFuture<? extends PlcReadResponse> read = getReader().read(new PlcReadRequest(dataType, field));
+        CompletableFuture<PlcReadResponse> read = plcReader.read(readRequest);
         try {
             PlcReadResponse plcReadResponse = read.get();
-            exchange.getIn().setBody(unwrapIfSingle(plcReadResponse.getResponseItems()));
+            exchange.getIn().setBody(unwrapIfSingle(plcReadResponse.getAllObjects("default")));
         } catch (InterruptedException | ExecutionException e) {
             exchange.setException(e);
         }
@@ -97,20 +97,16 @@ public class Plc4XPollingConsumer extends ServiceSupport implements PollingConsu
     @Override
     public Exchange receive(long timeout) {
         Exchange exchange = endpoint.createExchange();
-        CompletableFuture<? extends PlcReadResponse> read = getReader().read(new PlcReadRequest(dataType, field));
+        CompletableFuture<PlcReadResponse> read = plcReader.read(readRequest);
         try {
             PlcReadResponse plcReadResponse = read.get(timeout, TimeUnit.MILLISECONDS);
-            exchange.getIn().setBody(unwrapIfSingle(plcReadResponse.getResponseItems()));
+            exchange.getIn().setBody(unwrapIfSingle(plcReadResponse.getAllObjects("default")));
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             exchange.setException(e);
         }
         return exchange;
     }
 
-    public PlcReader getReader() {
-        return plcConnection.getReader().orElseThrow(() -> new RuntimeException("No reader avaiable"));
-    }
-
     @Override
     protected void doStart() {
         // We don't seem to need to do anything special here.
@@ -125,14 +121,14 @@ public class Plc4XPollingConsumer extends ServiceSupport implements PollingConsu
         }
     }
 
-    private Object unwrapIfSingle(List list) {
-        if (list.isEmpty()) {
+    private Object unwrapIfSingle(Collection collection) {
+        if (collection.isEmpty()) {
             return null;
         }
-        if (list.size() == 1) {
-            return list.get(0);
+        if (collection.size() == 1) {
+            return collection.iterator().next();
         }
-        return list;
+        return collection;
     }
 
 }
diff --git a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XProducer.java b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XProducer.java
index 0995a24..3619d61 100644
--- a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XProducer.java
+++ b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/Plc4XProducer.java
@@ -27,43 +27,38 @@ import org.apache.plc4x.java.api.connection.PlcWriter;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
-import org.apache.plc4x.java.api.messages.items.PlcWriteRequestItem;
-import org.apache.plc4x.java.api.model.PlcField;
 
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class Plc4XProducer extends DefaultAsyncProducer {
-    @SuppressWarnings("unused")
-    private Plc4XEndpoint endpoint;
     private PlcConnection plcConnection;
+    private PlcWriter plcWriter;
     private AtomicInteger openRequests;
 
     public Plc4XProducer(Plc4XEndpoint endpoint) throws PlcException {
         super(endpoint);
-        this.endpoint = endpoint;
         String plc4xURI = endpoint.getEndpointUri().replaceFirst("plc4x:/?/?", "");
         plcConnection = endpoint.getPlcDriverManager().getConnection(plc4xURI);
+        plcWriter = plcConnection.getWriter().orElseThrow(() -> new PlcException("This connection doesn't support writing."));
         openRequests = new AtomicInteger();
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public void process(Exchange exchange) throws Exception {
         Message in = exchange.getIn();
-        PlcField field = in.getHeader(Constants.ADDRESS_HEADER, PlcField.class);
+        String fieldName = in.getHeader(Constants.FIELD_NAME_HEADER, String.class);
+        String fieldQuery = in.getHeader(Constants.FIELD_QUERY_HEADER, String.class);
         Object body = in.getBody();
-        PlcWriteRequest.Builder builder = PlcWriteRequest.builder();
+        PlcWriteRequest.Builder builder = plcWriter.writeRequestBuilder();
         if (body instanceof List) {
             List<?> bodyList = in.getBody(List.class);
-            bodyList
-                .stream()
-                .map(o -> (PlcWriteRequestItem<?>) new PlcWriteRequestItem(o.getClass(), field, o))
-                .forEach(builder::addItem);
+            Object[] values = bodyList.toArray();
+            builder.addItem(fieldName, fieldQuery, values);
         } else {
             Object value = in.getBody(Object.class);
-            builder.addItem(field, value);
+            builder.addItem(fieldName, fieldQuery, value);
         }
         PlcWriter plcWriter = plcConnection.getWriter().orElseThrow(() -> new IllegalArgumentException("Writer for driver not found"));
         CompletableFuture<? extends PlcWriteResponse> completableFuture = plcWriter.write(builder.build());
diff --git a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/ResponseItemTypeConverter.java b/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/ResponseItemTypeConverter.java
deleted file mode 100644
index 467768c..0000000
--- a/integrations/apache-camel/src/main/java/org/apache/plc4x/camel/ResponseItemTypeConverter.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   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.camel;
-
-import org.apache.camel.Converter;
-import org.apache.plc4x.java.api.messages.items.PlcReadResponseItem;
-
-import java.util.stream.Collectors;
-
-@Converter
-public class ResponseItemTypeConverter {
-
-    @Converter
-    public static String toString(PlcReadResponseItem<?> responseItem) {
-        return responseItem.getValues().stream().map(String::valueOf).collect(Collectors.joining(","));
-    }
-
-}
diff --git a/integrations/apache-camel/src/main/resources/META-INF/services/org/apache/camel/TypeConverter b/integrations/apache-camel/src/main/resources/META-INF/services/org/apache/camel/TypeConverter
deleted file mode 100644
index e1897d1..0000000
--- a/integrations/apache-camel/src/main/resources/META-INF/services/org/apache/camel/TypeConverter
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-org.apache.plc4x.camel.ResponseItemTypeConverter
\ No newline at end of file
diff --git a/integrations/apache-edgent/src/main/java/org/apache/plc4x/edgent/PlcConnectionAdapter.java b/integrations/apache-edgent/src/main/java/org/apache/plc4x/edgent/PlcConnectionAdapter.java
index 06975f3..9e76e2a 100644
--- a/integrations/apache-edgent/src/main/java/org/apache/plc4x/edgent/PlcConnectionAdapter.java
+++ b/integrations/apache-edgent/src/main/java/org/apache/plc4x/edgent/PlcConnectionAdapter.java
@@ -154,7 +154,6 @@ public class PlcConnectionAdapter implements AutoCloseable {
             PlcField field = null;
             try {
                 connection = getConnection();
-                field = connection.prepareField(fieldQuery);
                 PlcReader reader = connection.getReader()
                     .orElseThrow(() -> new PlcException("This connection doesn't support reading"));
                 PlcReadRequest readRequest = reader.readRequestBuilder().addItem(FIELD_NAME, fieldQuery).build();
diff --git a/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/PlcConnectionAdapterTest.java b/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/PlcConnectionAdapterTest.java
index 8272b7b..cd903f3 100644
--- a/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/PlcConnectionAdapterTest.java
+++ b/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/PlcConnectionAdapterTest.java
@@ -90,28 +90,6 @@ public class PlcConnectionAdapterTest {
         adapter.close();
     }
 
-    @Test
-    @Category(FastTests.class)
-    public void testCheckDatatype() {
-        PlcConnectionAdapter.checkDatatype(Boolean.class);
-        PlcConnectionAdapter.checkDatatype(Byte.class);
-        PlcConnectionAdapter.checkDatatype(Short.class);
-        PlcConnectionAdapter.checkDatatype(Integer.class);
-        PlcConnectionAdapter.checkDatatype(Float.class);
-        PlcConnectionAdapter.checkDatatype(String.class);
-        PlcConnectionAdapter.checkDatatype(Calendar.class);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testLongDataTypeIsInvalid() {
-        PlcConnectionAdapter.checkDatatype(Long.class);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testDoubleDataTypeIsInvalid() {
-        PlcConnectionAdapter.checkDatatype(Double.class);
-    }
-
     private <T> void checkRead(MockConnection connection, TypeSafePlcReadRequest<T> request, T value) throws InterruptedException, ExecutionException {
         // this is really a tests of our mock tooling but knowing it's behaving as expected
         // will help identify problems in the adapter/supplier/consumer
diff --git a/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/mock/MockConnection.java b/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/mock/MockConnection.java
index ed60240..0357bfd 100644
--- a/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/mock/MockConnection.java
+++ b/integrations/apache-edgent/src/test/java/org/apache/plc4x/edgent/mock/MockConnection.java
@@ -70,6 +70,11 @@ public class MockConnection extends org.apache.plc4x.java.base.connection.MockCo
     }
 
     @Override
+    public PlcReadRequest.Builder readRequestBuilder() {
+        return null;
+    }
+
+    @Override
     public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
         curReadCnt++;
         if (readExceptionTriggerCount > 0 && curReadCnt == readExceptionTriggerCount) {
@@ -97,6 +102,11 @@ public class MockConnection extends org.apache.plc4x.java.base.connection.MockCo
         return CompletableFuture.completedFuture(response);
     }
 
+    @Override
+    public PlcWriteRequest.Builder writeRequestBuilder() {
+        return null;
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java
index c09c08a..c508217 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcConnection.java
@@ -19,8 +19,6 @@ under the License.
 package org.apache.plc4x.java.api.connection;
 
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.api.model.PlcField;
 
 import java.util.Optional;
 
@@ -55,15 +53,6 @@ public interface PlcConnection extends AutoCloseable {
     @Override
     void close() throws Exception;
 
-    /**
-     * Parses a PLC/protocol dependent field string into an PlcField object.
-     *
-     * @param fieldString String representation of an address for the current type of PLC/protocol.
-     * @return PlcField object identifying a field for the current type of PLC/protocol.
-     * @throws PlcInvalidFieldException an exception if there was a problem parsing the address string.
-     */
-    PlcField prepareField(String fieldString) throws PlcInvalidFieldException;
-
     Optional<PlcReader> getReader();
 
     Optional<PlcWriter> getWriter();
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcSubscriber.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcSubscriber.java
index a46126d..65ef3f4 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcSubscriber.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/connection/PlcSubscriber.java
@@ -44,8 +44,8 @@ public interface PlcSubscriber {
      */
     CompletableFuture<PlcUnsubscriptionResponse> unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest);
 
-    PlcMessageBuilder<PlcSubscriptionRequest> subsciptionRequestBuilder();
+    PlcSubscriptionRequest.Builder subscriptionRequestBuilder();
 
-    PlcMessageBuilder<PlcUnsubscriptionRequest> unsubsciptionRequestBuilder();
+    PlcUnsubscriptionRequest.Builder unsubscriptionRequestBuilder();
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java
index f9bd49b..c1b378f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java
@@ -21,16 +21,11 @@ package org.apache.plc4x.java.api.messages;
 import org.apache.plc4x.java.api.model.PlcField;
 
 import java.util.Collection;
-import java.util.Map;
 
 public interface PlcFieldRequest extends PlcRequest {
 
-    Map<String, PlcField> getFields();
-
     Collection<String> getFieldNames();
 
     PlcField getField(String name);
 
-
-
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadRequest.java
index af9d29d..2b9a7d5 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadRequest.java
@@ -23,8 +23,6 @@ package org.apache.plc4x.java.api.messages;
  */
 public interface PlcReadRequest extends PlcFieldRequest {
 
-    PlcMessageBuilder<PlcReadRequest> builder();
-
     interface Builder extends PlcMessageBuilder<PlcReadRequest> {
         Builder addItem(String name, String fieldQuery);
     }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionEvent.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionEvent.java
index 30535be..4c333cf 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionEvent.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionEvent.java
@@ -18,6 +18,6 @@ under the License.
 */
 package org.apache.plc4x.java.api.messages;
 
-public interface PlcSubscriptionEvent {
+public interface PlcSubscriptionEvent extends PlcReadResponse {
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
index 4a501ab..fc95e00 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionRequest.java
@@ -18,8 +18,44 @@ under the License.
 */
 package org.apache.plc4x.java.api.messages;
 
+import java.time.Duration;
+
 public interface PlcSubscriptionRequest extends PlcFieldRequest {
 
     PlcMessageBuilder<PlcSubscriptionRequest> builder();
 
+    interface Builder extends PlcMessageBuilder<PlcSubscriptionRequest> {
+        /**
+         * Adds a new field to the to be constructed request which should be polled cyclically.
+         *
+         * @param name alias of the field.
+         * @param fieldQuery field query string for accessing the field.
+         * @param pollingInterval interval, in which the field should be polled.
+         * @return
+         */
+        PlcSubscriptionRequest.Builder addCyclicField(String name, String fieldQuery, Duration pollingInterval);
+
+        /**
+         * Adds a new field to the to be constructed request which should be updated as soon as
+         * a value changes in the PLC.
+         *
+         * @param name alias of the field.
+         * @param fieldQuery field query string for accessing the field.
+         * @return
+         */
+        PlcSubscriptionRequest.Builder addChangeOfStateField(String name, String fieldQuery);
+
+        /**
+         * Adds a new subscription to the to be constructed request which should be updated
+         * as soon as an event occurs.
+         *
+         * REMARK: We will have to see if this signature is correct as soon as we start using this type of subscription.
+         *
+         * @param name alias of the field.
+         * @param fieldQuery field query string for accessing the field.
+         * @return
+         */
+        PlcSubscriptionRequest.Builder addEventField(String name, String fieldQuery);
+    }
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
index effb1d3..a868e28 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcSubscriptionResponse.java
@@ -18,6 +18,10 @@ under the License.
 */
 package org.apache.plc4x.java.api.messages;
 
+import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
+
 public interface PlcSubscriptionResponse extends PlcFieldResponse<PlcSubscriptionRequest> {
 
+    PlcSubscriptionHandle getSubscriptionHandle(String name);
+
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
index e8171f1..57a69b6 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcUnsubscriptionRequest.java
@@ -18,7 +18,7 @@ under the License.
 */
 package org.apache.plc4x.java.api.messages;
 
-import java.time.Duration;
+import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 
 public interface PlcUnsubscriptionRequest extends PlcFieldRequest {
 
@@ -27,33 +27,10 @@ public interface PlcUnsubscriptionRequest extends PlcFieldRequest {
          * Adds a new field to the to be constructed request which should be polled cyclically.
          *
          * @param name alias of the field.
-         * @param fieldQuery field query string for accessing the field.
-         * @param pollingInterval interval, in which the field should be polled.
+         * @param handle subscription handle containing information about the subscription.
          * @return
          */
-        PlcReadRequest.Builder addCyclicField(String name, String fieldQuery, Duration pollingInterval);
-
-        /**
-         * Adds a new field to the to be constructed request which should be updated as soon as
-         * a value changes in the PLC.
-         *
-         * @param name alias of the field.
-         * @param fieldQuery field query string for accessing the field.
-         * @return
-         */
-        PlcReadRequest.Builder addChangeOfStateField(String name, String fieldQuery);
-
-        /**
-         * Adds a new subscription to the to be constructed request which should be updated
-         * as soon as an event occurs.
-         *
-         * REMARK: We will have to see if this signature is correct as soon as we start using this type of subscription.
-         *
-         * @param name alias of the field.
-         * @param fieldQuery field query string for accessing the field.
-         * @return
-         */
-        PlcReadRequest.Builder addEventField(String name, String fieldQuery);
+        PlcUnsubscriptionRequest.Builder addField(String name, PlcSubscriptionHandle handle);
     }
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
index 4d08985..9ead9b0 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java
@@ -24,11 +24,13 @@ import java.time.LocalTime;
 
 public interface PlcWriteRequest extends PlcFieldRequest {
 
+    byte[][] getValues(String name);
+
     interface Builder extends PlcMessageBuilder<PlcWriteRequest> {
 
-        PlcReadRequest.Builder addItem(String name, String fieldQuery, byte[]... values);
+        PlcWriteRequest.Builder addItem(String name, String fieldQuery, byte[]... values);
 
-        PlcReadRequest.Builder addItem(String name, String fieldQuery, Object... values);
+        PlcWriteRequest.Builder addItem(String name, String fieldQuery, Object... values);
 
         PlcWriteRequest.Builder addItem(String name, String fieldQuery, Boolean... values);
 
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
index eee3f02..bb1b11f 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/AbstractPlcConnection.java
@@ -101,7 +101,7 @@ public abstract class AbstractPlcConnection implements PlcConnection {
     }
 
     @Override
-    public Optional<PlcReader> getReader() {
+    public Optional<PlcReader>getReader() {
         if (this instanceof PlcReader) {
             return Optional.of((PlcReader) this);
         }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java
similarity index 63%
copy from plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java
copy to plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java
index f9bd49b..7bfc80b 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcFieldRequest.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java
@@ -16,21 +16,17 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.api.messages;
+package org.apache.plc4x.java.base.connection;
 
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcClientDatatype;
 
-import java.util.Collection;
-import java.util.Map;
-
-public interface PlcFieldRequest extends PlcRequest {
-
-    Map<String, PlcField> getFields();
-
-    Collection<String> getFieldNames();
-
-    PlcField getField(String name);
+public interface PlcFieldHandler {
 
+    PlcField createField(String fieldQuery) throws PlcInvalidFieldException;
 
+    byte[][] encode(PlcField field, PlcClientDatatype clientDatatype, Object[] values);
+    Object[] decode(PlcField field, PlcClientDatatype clientDatatype, byte[][] rawData);
 
 }
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadRequest.java
new file mode 100644
index 0000000..a330097
--- /dev/null
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadRequest.java
@@ -0,0 +1,83 @@
+/*
+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.base.messages;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.base.connection.PlcFieldHandler;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class DefaultPlcReadRequest implements PlcReadRequest {
+
+    private Map<String, PlcField> fields;
+
+    private DefaultPlcReadRequest() {
+        this.fields = new TreeMap<>();
+    }
+
+    private DefaultPlcReadRequest(Map<String, PlcField> fields) {
+        this.fields = fields;
+    }
+
+    @Override
+    public Collection<String> getFieldNames() {
+        return fields.keySet();
+    }
+
+    @Override
+    public PlcField getField(String name) {
+        return fields.get(name);
+    }
+
+    public static class DefaultPlcReadRequestBuilder implements PlcReadRequest.Builder {
+
+        private final PlcFieldHandler fieldHandler;
+        private final Map<String, String> fields;
+
+        public DefaultPlcReadRequestBuilder(PlcFieldHandler fieldHandler) {
+            this.fieldHandler = fieldHandler;
+            fields = new TreeMap<>();
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery) {
+            if(fields.containsKey(name)) {
+                throw new PlcRuntimeException("Duplicate field definition '" + name + "'");
+            }
+            fields.put(name, fieldQuery);
+            return this;
+        }
+
+        @Override
+        public PlcReadRequest build() {
+            Map<String, PlcField> parsedFields = new TreeMap<>();
+            fields.forEach((name, fieldQuery) -> {
+                PlcField parsedField = fieldHandler.createField(fieldQuery);
+                parsedFields.put(name, parsedField);
+            });
+            return new DefaultPlcReadRequest(parsedFields);
+        }
+
+    }
+
+}
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java
new file mode 100644
index 0000000..7053220
--- /dev/null
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java
@@ -0,0 +1,324 @@
+/*
+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.base.messages;
+
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Collection;
+import java.util.Map;
+
+public class DefaultPlcReadResponse implements PlcReadResponse {
+
+    @Override
+    public int getNumValues(String name) {
+        return 0;
+    }
+
+    @Override
+    public boolean isRaw(String name) {
+        return false;
+    }
+
+    @Override
+    public byte[] getRaw(String name) {
+        return new byte[0];
+    }
+
+    @Override
+    public byte[] getRaw(String name, int index) {
+        return new byte[0];
+    }
+
+    @Override
+    public Collection<byte[]> getAllRaws(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isObject(String name) {
+        return false;
+    }
+
+    @Override
+    public Object getObject(String name) {
+        return null;
+    }
+
+    @Override
+    public Object getObject(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Object> getAllObjects(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isBoolean(String name) {
+        return false;
+    }
+
+    @Override
+    public Boolean getBoolean(String name) {
+        return null;
+    }
+
+    @Override
+    public Boolean getBoolean(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Boolean> getAllBooleans(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isByte(String name) {
+        return false;
+    }
+
+    @Override
+    public Byte getByte(String name) {
+        return null;
+    }
+
+    @Override
+    public Byte getByte(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Byte> getAllBytes(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isShort(String name) {
+        return false;
+    }
+
+    @Override
+    public Short getShort(String name) {
+        return null;
+    }
+
+    @Override
+    public Short getShort(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Short> getAllShorts(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isInteger(String name) {
+        return false;
+    }
+
+    @Override
+    public Integer getInteger(String name) {
+        return null;
+    }
+
+    @Override
+    public Integer getInteger(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Integer> getAllIntegers(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isLong(String name) {
+        return false;
+    }
+
+    @Override
+    public Long getLong(String name) {
+        return null;
+    }
+
+    @Override
+    public Long getLong(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Long> getAllLongs(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isFloat(String name) {
+        return false;
+    }
+
+    @Override
+    public Float getFloat(String name) {
+        return null;
+    }
+
+    @Override
+    public Float getFloat(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Float> getAllFloats(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isDouble(String name) {
+        return false;
+    }
+
+    @Override
+    public Double getDouble(String name) {
+        return null;
+    }
+
+    @Override
+    public Double getDouble(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<Double> getAllDoubles(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isString(String name) {
+        return false;
+    }
+
+    @Override
+    public String getString(String name) {
+        return null;
+    }
+
+    @Override
+    public String getString(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<String> getAllStrings(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isTime(String name) {
+        return false;
+    }
+
+    @Override
+    public LocalTime getTime(String name) {
+        return null;
+    }
+
+    @Override
+    public LocalTime getTime(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<LocalTime> getAllTimes(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isDate(String name) {
+        return false;
+    }
+
+    @Override
+    public LocalDate getDate(String name) {
+        return null;
+    }
+
+    @Override
+    public LocalDate getDate(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<LocalDate> getAllDates(String name) {
+        return null;
+    }
+
+    @Override
+    public boolean isDateTime(String name) {
+        return false;
+    }
+
+    @Override
+    public LocalDateTime getDateTime(String name) {
+        return null;
+    }
+
+    @Override
+    public LocalDateTime getDateTime(String name, int index) {
+        return null;
+    }
+
+    @Override
+    public Collection<LocalDateTime> getAllDateTimes(String name) {
+        return null;
+    }
+
+    @Override
+    public Map<String, PlcField> getFields() {
+        return null;
+    }
+
+    @Override
+    public Collection<String> getFieldNames() {
+        return null;
+    }
+
+    @Override
+    public PlcField getField(String name) {
+        return null;
+    }
+
+    @Override
+    public PlcResponseCode getResponseCode(String name) {
+        return null;
+    }
+
+    @Override
+    public PlcReadRequest getRequest() {
+        return null;
+    }
+
+}
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java
new file mode 100644
index 0000000..d060218
--- /dev/null
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java
@@ -0,0 +1,180 @@
+/*
+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.base.messages;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcClientDatatype;
+import org.apache.plc4x.java.base.connection.PlcFieldHandler;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class DefaultPlcWriteRequest implements PlcWriteRequest {
+
+    private final Map<String, Item> fields;
+
+    private DefaultPlcWriteRequest(Map<String, Item> fields) {
+        this.fields = fields;
+    }
+
+    @Override
+    public Collection<String> getFieldNames() {
+        return fields.keySet();
+    }
+
+    @Override
+    public PlcField getField(String name) {
+        return fields.get(name).field;
+    }
+
+    @Override
+    public byte[][] getValues(String name) {
+        return fields.get(name).values;
+    }
+
+    public static class Builder implements PlcWriteRequest.Builder {
+
+        private final PlcFieldHandler fieldHandler;
+        private final Map<String, BuilderItem> fields;
+
+        public Builder(PlcFieldHandler fieldHandler) {
+            this.fieldHandler = fieldHandler;
+            fields = new TreeMap<>();
+        }
+
+        @Override
+        public PlcWriteRequest.Builder addItem(String name, String fieldQuery, byte[]... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.RAW);
+        }
+
+        @Override
+        public PlcWriteRequest.Builder addItem(String name, String fieldQuery, Object... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.OBJECT);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Boolean... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.BOOLEAN);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Byte... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.BYTE);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Short... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.SHORT);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Integer... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.INTEGER);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Long... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.LONG);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Float... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.FLOAT);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, Double... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.DOUBLE);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, String... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.STRING);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, LocalTime... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.TIME);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, LocalDate... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.DATE);
+        }
+
+        @Override
+        public Builder addItem(String name, String fieldQuery, LocalDateTime... values) {
+            return addItem(name, fieldQuery, values, PlcClientDatatype.DATE_TIME);
+        }
+
+        @Override
+        public PlcWriteRequest build() {
+            Map<String, DefaultPlcWriteRequest.Item> parsedFields = new TreeMap<>();
+            fields.forEach((name, builderItem) -> {
+                // Compile the query string.
+                PlcField parsedField = fieldHandler.createField(builderItem.fieldQuery);
+                // Encode the payload.
+                byte[][] rawData = fieldHandler.encode(parsedField, builderItem.clientDatatype, builderItem.values);
+                parsedFields.put(name, new DefaultPlcWriteRequest.Item(parsedField, rawData));
+            });
+            return new DefaultPlcWriteRequest(parsedFields);
+        }
+
+        private Builder addItem(String name, String fieldQuery, Object[] values, PlcClientDatatype clientDatatype) {
+            if(fields.containsKey(name)) {
+                throw new PlcRuntimeException("Duplicate field definition '" + name + "'");
+            }
+            fields.put(name, new BuilderItem(fieldQuery, clientDatatype, values));
+            return this;
+        }
+
+        private static class BuilderItem {
+
+            private final String fieldQuery;
+            private final PlcClientDatatype clientDatatype;
+            private final Object[] values;
+
+            private BuilderItem(String fieldQuery, PlcClientDatatype clientDatatype, Object[] values) {
+                this.fieldQuery = fieldQuery;
+                this.clientDatatype = clientDatatype;
+                this.values = values;
+            }
+        }
+
+    }
+
+    private static class Item {
+
+        private final PlcField field;
+        private final byte[][] values;
+
+        private Item(PlcField field, byte[][] values) {
+            this.field = field;
+            this.values = values;
+        }
+
+    }
+
+}
diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteResponse.java
similarity index 57%
copy from plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java
copy to plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteResponse.java
index f8897f7..ef1fd87 100644
--- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteResponse.java
@@ -16,30 +16,40 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.base.connection;
+package org.apache.plc4x.java.base.messages;
 
-import io.netty.channel.ChannelHandler;
+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.api.types.PlcResponseCode;
 
-import java.util.concurrent.CompletableFuture;
+import java.util.Collection;
+import java.util.Map;
 
-public class MockConnection extends AbstractPlcConnection {
+public class DefaultPlcWriteResponse implements PlcWriteResponse {
 
-    public MockConnection() {
-        super(new TestChannelFactory());
+    @Override
+    public Map<String, PlcField> getFields() {
+        return null;
+    }
+
+    @Override
+    public Collection<String> getFieldNames() {
+        return null;
     }
 
-    public MockConnection(boolean awaitSessionSetupComplete) {
-        super(new TestChannelFactory(), awaitSessionSetupComplete);
+    @Override
+    public PlcField getField(String name) {
+        return null;
     }
 
     @Override
-    protected ChannelHandler getChannelHandler(CompletableFuture<Void> sessionSetupCompleteFuture) {
+    public PlcResponseCode getResponseCode(String name) {
         return null;
     }
 
     @Override
-    public PlcField prepareField(String fieldString) {
+    public PlcWriteRequest getRequest() {
         return null;
     }
 
diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java
index f8897f7..3c64768 100644
--- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java
+++ b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/connection/MockConnection.java
@@ -38,9 +38,4 @@ public class MockConnection extends AbstractPlcConnection {
         return null;
     }
 
-    @Override
-    public PlcField prepareField(String fieldString) {
-        return null;
-    }
-
 }
diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/util/Junit5Backport.java b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/util/Junit5Backport.java
index 811df2f..84e6f26 100644
--- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/util/Junit5Backport.java
+++ b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/util/Junit5Backport.java
@@ -37,4 +37,5 @@ public class Junit5Backport {
     public interface Acceptor<T extends Exception> {
         void accept() throws T;
     }
+
 }
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
index 13ff259..86b7a7d 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.s7.connection;
 import io.netty.channel.*;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.configuration2.SystemConfiguration;
+import org.apache.commons.lang3.NotImplementedException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.plc4x.java.api.connection.PlcReader;
 import org.apache.plc4x.java.api.connection.PlcWriter;
@@ -31,11 +32,15 @@ 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.api.types.PlcClientDatatype;
 import org.apache.plc4x.java.base.connection.AbstractPlcConnection;
 import org.apache.plc4x.java.base.connection.ChannelFactory;
+import org.apache.plc4x.java.base.connection.PlcFieldHandler;
 import org.apache.plc4x.java.base.connection.TcpSocketChannelFactory;
 import org.apache.plc4x.java.base.events.ConnectEvent;
 import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.DefaultPlcReadRequest;
+import org.apache.plc4x.java.base.messages.DefaultPlcWriteRequest;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
 import org.apache.plc4x.java.isoontcp.netty.IsoOnTcpProtocol;
 import org.apache.plc4x.java.isotp.netty.IsoTPProtocol;
@@ -43,8 +48,6 @@ import org.apache.plc4x.java.isotp.netty.model.tpdus.DisconnectRequestTpdu;
 import org.apache.plc4x.java.isotp.netty.model.types.DeviceGroup;
 import org.apache.plc4x.java.isotp.netty.model.types.DisconnectReason;
 import org.apache.plc4x.java.isotp.netty.model.types.TpduSize;
-import org.apache.plc4x.java.s7.model.S7BitField;
-import org.apache.plc4x.java.s7.model.S7DataBlockField;
 import org.apache.plc4x.java.s7.model.S7Field;
 import org.apache.plc4x.java.s7.netty.Plc4XS7Protocol;
 import org.apache.plc4x.java.s7.netty.S7Protocol;
@@ -78,7 +81,7 @@ import java.util.concurrent.TimeoutException;
  * where the {bit-offset} is optional.
  * All Available Memory Areas for this mode are defined in the {@link MemoryArea} enum.
  */
-public class S7PlcConnection extends AbstractPlcConnection implements PlcReader, PlcWriter {
+public class S7PlcConnection extends AbstractPlcConnection implements PlcReader, PlcWriter, PlcFieldHandler {
 
     private static final int ISO_ON_TCP_PORT = 102;
 
@@ -241,17 +244,32 @@ public class S7PlcConnection extends AbstractPlcConnection implements PlcReader,
     }
 
     @Override
-    public PlcField prepareField(String fieldString) throws PlcInvalidFieldException {
-        if(S7DataBlockField.matches(fieldString)) {
-            return S7DataBlockField.of(fieldString);
+    public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+        if(S7DataBlockField.matches(fieldQuery)) {
+            return S7DataBlockField.of(fieldQuery);
         }
-        if(S7BitField.matches(fieldString)) {
-            return S7BitField.of(fieldString);
+        if(S7BitField.matches(fieldQuery)) {
+            return S7BitField.of(fieldQuery);
         }
-        if(S7Field.matches(fieldString)) {
-            return S7Field.of(fieldString);
+        if(S7Field.matches(fieldQuery)) {
+            return S7Field.of(fieldQuery);
         }
-        throw new PlcInvalidFieldException(fieldString);
+        throw new PlcInvalidFieldException(fieldQuery);
+    }
+
+    @Override
+    public byte[][] encode(PlcField field, PlcClientDatatype clientDatatype, Object[] values) {
+        throw new NotImplementedException("Not implemented ...");
+    }
+
+    @Override
+    public Object[] decode(PlcField field, PlcClientDatatype clientDatatype, byte[][] rawData) {
+        throw new NotImplementedException("Not implemented ...");
+    }
+
+    @Override
+    public PlcReadRequest.Builder readRequestBuilder() {
+        return new DefaultPlcReadRequest.DefaultPlcReadRequestBuilder(this);
     }
 
     @Override
@@ -266,6 +284,11 @@ public class S7PlcConnection extends AbstractPlcConnection implements PlcReader,
     }
 
     @Override
+    public PlcWriteRequest.Builder writeRequestBuilder() {
+        return new DefaultPlcWriteRequest.Builder(this);
+    }
+
+    @Override
     public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) {
         CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
         PlcRequestContainer<PlcWriteRequest, PlcWriteResponse> container =
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7BitField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7BitField.java
deleted file mode 100644
index 27a9d5e..0000000
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7BitField.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  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.s7.model;
-
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.s7.netty.model.types.MemoryArea;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class S7BitField extends S7Field {
-
-    private static final Pattern ADDRESS_PATTERN =
-        Pattern.compile("^(?<memoryArea>.*?)/(?<byteOffset>\\d{1,4})/(?<bitOffset>\\d)");
-
-    public static boolean matches(String addressString) {
-        return ADDRESS_PATTERN.matcher(addressString).matches();
-    }
-
-    public static S7BitField of(String fieldString) throws PlcInvalidFieldException {
-        Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
-        if (!matcher.matches()) {
-            throw new PlcInvalidFieldException(fieldString, ADDRESS_PATTERN);
-        }
-        MemoryArea memoryArea = MemoryArea.valueOf(matcher.group("memoryArea"));
-        short byteOffset = Short.parseShort(matcher.group("byteOffset"));
-        byte bitOffset = Byte.valueOf(matcher.group("bitOffset"));
-        return new S7BitField(memoryArea, byteOffset, bitOffset);
-    }
-
-    private final byte bitOffset;
-
-    public S7BitField(MemoryArea memoryArea, short byteOffset, byte bitOffset) {
-        super(memoryArea, byteOffset);
-        this.bitOffset = bitOffset;
-    }
-
-    public byte getBitOffset() {
-        return bitOffset;
-    }
-
-}
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7DataBlockField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7DataBlockField.java
deleted file mode 100644
index 12526ab..0000000
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7DataBlockField.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  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.s7.model;
-
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
-import org.apache.plc4x.java.s7.netty.model.types.MemoryArea;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class S7DataBlockField extends S7Field {
-
-    private static final Pattern ADDRESS_PATTERN =
-        Pattern.compile("^DATA_BLOCKS/(?<blockNumber>\\d{1,4})/(?<byteOffset>\\d{1,4})");
-
-    public static boolean matches(String fieldString) {
-        return ADDRESS_PATTERN.matcher(fieldString).matches();
-    }
-
-    public static S7DataBlockField of(String fieldString) throws PlcInvalidFieldException {
-        Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
-        if (!matcher.matches()) {
-            throw new PlcInvalidFieldException(fieldString, ADDRESS_PATTERN);
-        }
-        int datablockNumber = Integer.parseInt(matcher.group("blockNumber"));
-        int datablockByteOffset = Integer.parseInt(matcher.group("byteOffset"));
-        return new S7DataBlockField((short) datablockNumber, (short) datablockByteOffset);
-    }
-
-    private final short dataBlockNumber;
-
-    public S7DataBlockField(short dataBlockNumber, short byteOffset) {
-        super(MemoryArea.DATA_BLOCKS, byteOffset);
-        this.dataBlockNumber = dataBlockNumber;
-    }
-
-    public short getDataBlockNumber() {
-        return dataBlockNumber;
-    }
-
-}
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
index 620c057..20b12d6 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
@@ -21,35 +21,79 @@ package org.apache.plc4x.java.s7.model;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.s7.netty.model.types.MemoryArea;
+import org.apache.plc4x.java.s7.types.S7DataType;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public class S7Field implements PlcField {
 
+    // %I0.1:BOOL           <-- Digital Input
+    // %IW64:REAL           <-- Analog Input
+    // %Q0.4:BOOL           <-- Digital Output
+    // %DB1.DBX38.1:BOOL    <-- Memory block DB1
+
     private static final Pattern ADDRESS_PATTERN =
-        Pattern.compile("^(?<memoryArea>.*?)/(?<byteOffset>\\d{1,4})?");
+        Pattern.compile("^%(?<memoryArea>.)(?<transferSizeCode>.?)(?<byteOffset>\\d{1,4})(.(?<bitOffset>[0-7]))?:(?<dataType>.+)");
+    private static final Pattern DATA_BLOCK_ADDRESS_PATTERN =
+        Pattern.compile("^%DB(?<blockNumber>\\d{1,4}).DB(?<transferSizeCode>.?)(?<byteOffset>\\d{1,4})(.(?<bitOffset>[0-7]))?:(?<dataType>.+)");
 
     public static boolean matches(String fieldString) {
-        return ADDRESS_PATTERN.matcher(fieldString).matches();
+        return DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString).matches() ||
+            ADDRESS_PATTERN.matcher(fieldString).matches();
     }
 
     public static S7Field of(String fieldString) throws PlcInvalidFieldException {
-        Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
-        if (!matcher.matches()) {
-            throw new PlcInvalidFieldException(fieldString, ADDRESS_PATTERN);
+        Matcher matcher = DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString);
+        if(matcher.matches()) {
+            S7DataType dataType = S7DataType.valueOf(matcher.group("dataType"));
+            String transferSizeCode = matcher.group("transferSizeCode");
+            if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
+                throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
+                    "' doesn't match specified data type '" + dataType.name() + "'");
+            }
+            MemoryArea memoryArea = MemoryArea.INSTANCE_DATA_BLOCKS;
+            short byteOffset = Short.parseShort(matcher.group("byteOffset"));
+            short bitOffset = 0;
+            if(matcher.group("bitOffset") != null) {
+                bitOffset = Short.parseShort(matcher.group("bitOffset"));
+            }
+            return new S7Field(dataType, memoryArea, byteOffset, bitOffset);
+        } else {
+            matcher = ADDRESS_PATTERN.matcher(fieldString);
+            if (matcher.matches()) {
+                S7DataType dataType = S7DataType.valueOf(matcher.group("dataType"));
+                String transferSizeCode = matcher.group("transferSizeCode");
+                if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
+                    throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
+                        "' doesn't match specified data type '" + dataType.name() + "'");
+                }
+                MemoryArea memoryArea = MemoryArea.valueOf(matcher.group("memoryArea"));
+                short byteOffset = Short.parseShort(matcher.group("byteOffset"));
+                short bitOffset = 0;
+                if(matcher.group("bitOffset") != null) {
+                    bitOffset = Short.parseShort(matcher.group("bitOffset"));
+                }
+                return new S7Field(dataType, memoryArea, byteOffset, bitOffset);
+            }
         }
-        MemoryArea memoryArea = MemoryArea.valueOf(matcher.group("memoryArea"));
-        short byteOffset = Short.parseShort(matcher.group("byteOffset"));
-        return new S7Field(memoryArea, byteOffset);
+        throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
     }
 
+    private final S7DataType dataType;
     private final MemoryArea memoryArea;
     private final short byteOffset;
+    private final short bitOffset;
 
-    public S7Field(MemoryArea memoryArea, short byteOffset) {
+    public S7Field(S7DataType dataType, MemoryArea memoryArea, short byteOffset, short bitOffset) {
+        this.dataType = dataType;
         this.memoryArea = memoryArea;
         this.byteOffset = byteOffset;
+        this.bitOffset = bitOffset;
+    }
+
+    public S7DataType getDataType() {
+        return dataType;
     }
 
     public MemoryArea getMemoryArea() {
@@ -60,4 +104,8 @@ public class S7Field implements PlcField {
         return byteOffset;
     }
 
+    public short getBitOffset() {
+        return bitOffset;
+    }
+
 }
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
index b4a3a8b..88f56e4 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
@@ -34,9 +34,7 @@ import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
 import org.apache.plc4x.java.base.events.ConnectedEvent;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
-import org.apache.plc4x.java.s7.model.S7DataBlockField;
 import org.apache.plc4x.java.s7.model.S7Field;
-import org.apache.plc4x.java.s7.model.S7BitField;
 import org.apache.plc4x.java.s7.netty.events.S7ConnectedEvent;
 import org.apache.plc4x.java.s7.netty.model.messages.S7Message;
 import org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage;
@@ -168,10 +166,17 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec<S7Message, PlcRequ
         List<VarPayloadItem> payloadItems = new LinkedList<>();
 
         PlcWriteRequest writeRequest = (PlcWriteRequest) msg.getRequest();
-        for (PlcWriteRequestItem requestItem : writeRequest.getRequestItems()) {
+        for (String fieldName : writeRequest.getFieldNames()) {
+            PlcField field = writeRequest.getField(fieldName);
+            if(!(field instanceof S7Field)) {
+                throw new PlcException("The field should have been of type S7Field");
+            }
+
+            S7Field s7Field = (S7Field) field;
+
             // Try to get the correct S7 transport size for the given data type.
             // (Map PLC4X data type to S7 data type)
-            TransportSize transportSize = encodeTransportSize(requestItem.getDatatype());
+            TransportSize transportSize = encodeTransportSize(s7Field.getDatatype());
             if (transportSize == null) {
                 throw new PlcException("Unknown transport size for datatype " + requestItem.getDatatype());
             }
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7DataType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7DataType.java
index a5f8fae..30b40a6 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7DataType.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7DataType.java
@@ -117,39 +117,32 @@ public enum S7DataType {
      * that matches the provided size-code.
      * - If a sub-type was provided, all we do, is check if the size-code matches
      *
-     * @param javaType java type used in the request item
      * @param s7Type   type or sub-type provided (optional)
      * @param sizeCode size-code provided (optional)
      * @return best matching type.
      * @throws IllegalArgumentException no type with matching type and size-code was found.
      */
-    static S7DataType findMatchingType(Class<?> javaType, S7DataType s7Type, String sizeCode) throws IllegalArgumentException {
+    public static S7DataType findMatchingType(S7DataType s7Type, String sizeCode) throws IllegalArgumentException {
         assert s7Type != null;
 
-        if (javaType != null) {
-
-            if (sizeCode != null) {
-                // If this is a base type, we will try to check if we can select a better fitting sub-type.
-                if (s7Type.isBaseType()) {
-                    S7DataType subType = s7Type.getSubType(sizeCode);
-                    if (subType == null) {
-                        throw new IllegalArgumentException(String.format(
-                            "Selected base type %s does not have a sub-type for provided size code %s", s7Type, sizeCode));
-                    }
-                    s7Type = subType;
+        if (sizeCode != null) {
+            // If this is a base type, we will try to check if we can select a better fitting sub-type.
+            if (s7Type.isBaseType()) {
+                S7DataType subType = s7Type.getSubType(sizeCode);
+                if (subType == null) {
+                    throw new IllegalArgumentException(String.format(
+                        "Selected base type %s does not have a sub-type for provided size code %s", s7Type, sizeCode));
                 }
-                // If this is not a base type, we have to check if the sizeCode matches the selected sub-type.
-                else {
-                    if (!s7Type.getSizeCode().equals(sizeCode)) {
-                        throw new IllegalArgumentException(
-                            String.format("Selected data type %s does not match provided size code %s", s7Type, sizeCode));
-                    }
+                s7Type = subType;
+            }
+            // If this is not a base type, we have to check if the sizeCode matches the selected sub-type.
+            else {
+                if (!s7Type.getSizeCode().equals(sizeCode)) {
+                    throw new IllegalArgumentException(
+                        String.format("Selected data type %s does not match provided size code %s", s7Type, sizeCode));
                 }
             }
-
         }
-        // TODO: Check compatibility with the java-type.
-        return s7Type;
     }
 
 }
\ No newline at end of file
diff --git a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
index 883001b..235644a 100644
--- a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
+++ b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
@@ -22,9 +22,7 @@ package org.apache.plc4x.java.s7.connection;
 import org.apache.plc4x.java.api.exceptions.PlcException;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.isotp.netty.model.types.TpduSize;
-import org.apache.plc4x.java.s7.model.S7DataBlockField;
 import org.apache.plc4x.java.s7.model.S7Field;
-import org.apache.plc4x.java.s7.model.S7BitField;
 import org.apache.plc4x.java.s7.netty.model.types.MemoryArea;
 import org.junit.After;
 import org.junit.Before;
diff --git a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/model/S7FieldTests.java b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/model/S7FieldTests.java
index d7738dd..deddabc 100644
--- a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/model/S7FieldTests.java
+++ b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/model/S7FieldTests.java
@@ -29,6 +29,11 @@ import static org.junit.Assert.assertThat;
 
 public class S7FieldTests {
 
+    // %I0.1:BOOL           <-- Digital Input
+    // %IW64:REAL           <-- Analog Input
+    // %Q0.4:BOOL           <-- Digital Output
+    // %DB1.DBX38.1:BOOL    <-- Memory block DB1
+
     @Test
     @Category(FastTests.class)
     public void testS7Field() {
diff --git a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/netty/Plc4XS7ProtocolTest.java b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/netty/Plc4XS7ProtocolTest.java
index c86152e..4efaff0 100644
--- a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/netty/Plc4XS7ProtocolTest.java
+++ b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/netty/Plc4XS7ProtocolTest.java
@@ -25,8 +25,6 @@ import org.apache.plc4x.java.api.messages.specific.TypeSafePlcReadRequest;
 import org.apache.plc4x.java.api.messages.specific.TypeSafePlcWriteRequest;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
 import org.apache.plc4x.java.netty.NettyTestBase;
-import org.apache.plc4x.java.s7.model.S7BitField;
-import org.apache.plc4x.java.s7.model.S7DataBlockField;
 import org.apache.plc4x.java.s7.model.S7Field;
 import org.apache.plc4x.java.s7.netty.model.messages.S7ResponseMessage;
 import org.apache.plc4x.java.s7.netty.model.params.VarParameter;