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

cgarcia pushed a commit to branch feature/s7strings
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit b9b9307baa094e23447fc5e3671de10d0d821875
Author: Cesar Garcia <[email protected]>
AuthorDate: Tue Nov 28 20:33:24 2023 -0400

    Support for reading and writing to STRING type memory areas. Example of use 
is included.
---
 .../java/s7/readwrite/optimizer/S7Optimizer.java   |  27 +-
 .../s7/readwrite/protocol/S7ProtocolLogic.java     | 332 +++++++++++++++-
 .../plc4x/java/s7/readwrite/tag/S7ClkTag.java      |   2 +-
 .../java/s7/readwrite/tag/S7PlcTagHandler.java     |   6 +-
 .../plc4x/java/s7/readwrite/tag/S7StringTag.java   | 131 +++++++
 .../apache/plc4x/java/s7/readwrite/tag/S7Tag.java  | 105 +++--
 .../plc4j/s7event/PlcReadWriteStrings.java         | 434 +++++++++++++++++++++
 7 files changed, 961 insertions(+), 76 deletions(-)

diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
index 47bc4b8821..0487f65f94 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
@@ -38,6 +38,8 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import org.apache.plc4x.java.s7.readwrite.tag.S7StringTag;
 
 public class S7Optimizer extends BaseOptimizer {
 
@@ -63,16 +65,26 @@ public class S7Optimizer extends BaseOptimizer {
         int curResponseSize = EMPTY_READ_RESPONSE_SIZE;
 
         // List of all items in the current request.
+
         LinkedHashMap<String, PlcTag> curTags = new LinkedHashMap<>();
 
         for (String tagName : readRequest.getTagNames()) {
-
+           
+            //TODO: Individual processing of these types of tags. like 
S7StringTag
             if ((readRequest.getTag(tagName) instanceof S7SzlTag) ||
                 (readRequest.getTag(tagName) instanceof S7ClkTag)) {
                 curTags.put(tagName, readRequest.getTag(tagName));
                 continue;
             }
-
+            
+            if ((readRequest.getTag(tagName) instanceof S7StringTag)) { 
+                LinkedHashMap<String, PlcTag> strTags = new LinkedHashMap<>();
+                strTags.put(tagName, readRequest.getTag(tagName));
+                processedRequests.add(new DefaultPlcReadRequest(
+                ((DefaultPlcReadRequest) readRequest).getReader(), strTags));
+                continue;
+            }            
+            
             S7Tag tag = (S7Tag) readRequest.getTag(tagName);
 
             int readRequestItemSize = S7_ADDRESS_ANY_SIZE;
@@ -142,6 +154,17 @@ public class S7Optimizer extends BaseOptimizer {
         LinkedHashMap<String, TagValueItem> curTags = new LinkedHashMap<>();
 
         for (String tagName : writeRequest.getTagNames()) {
+            
+            if ((writeRequest.getTag(tagName) instanceof S7StringTag)) { 
+                LinkedHashMap<String, TagValueItem> strTags = new 
LinkedHashMap<>();
+                strTags.put(tagName, 
+                        new TagValueItem(writeRequest.getTag(tagName), 
+                                writeRequest.getPlcValue(tagName)));  
+                processedRequests.add(new DefaultPlcWriteRequest(
+                ((DefaultPlcWriteRequest) writeRequest).getWriter(), strTags));
+                continue;                
+            }
+                                    
             S7Tag tag = (S7Tag) writeRequest.getTag(tagName);
             PlcValue value = writeRequest.getPlcValue(tagName);
 
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index 032948be18..4bfed9bb73 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -61,6 +62,7 @@ import java.util.concurrent.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.logging.Level;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
@@ -306,6 +308,17 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
                 new S7PayloadUserData(payloadItems));
             return toPlcReadResponse(readRequest, 
readInternal(s7MessageRequest));
 
+        }  else if (request.getTags().get(0) instanceof S7StringTag) {
+            
+            List<S7ParameterReadVarRequest> parameterItems = new 
ArrayList<>(request.getNumberOfTags());
+            List<S7PayloadUserDataItem> payloadItems = new 
ArrayList<>(request.getNumberOfTags());            
+            encodePlcStringReadRequest(request, parameterItems, payloadItems);
+            
+            final S7MessageRequest s7MessageRequest = new S7MessageRequest(-1,
+                parameterItems.get(0),
+                null);
+            
+            return toPlcReadResponse(readRequest, 
readInternal(s7MessageRequest));
         }
 
 
@@ -414,6 +427,13 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
         if (!clkTags.isEmpty()) {
             return writeClk(writeRequest);
         }
+        
+        List<String> strTags = request.getTagNames().stream()
+            .filter(t -> request.getTag(t) instanceof S7StringTag)
+            .collect(Collectors.toList());
+        if (!strTags.isEmpty()) {
+            return writeString(writeRequest);
+        }        
 
         List<S7VarRequestParameterItem> parameterItems = new 
ArrayList<>(request.getNumberOfTags());
         List<S7VarPayloadDataItem> payloadItems = new 
ArrayList<>(request.getNumberOfTags());
@@ -524,6 +544,56 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
         return future;
     }
 
+    //TODO: Clean code
+    public CompletableFuture<PlcWriteResponse> writeString(PlcWriteRequest 
writeRequest) {
+        CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
+        DefaultPlcWriteRequest request = (DefaultPlcWriteRequest) writeRequest;
+
+        List<S7VarRequestParameterItem> parameterItems = new 
ArrayList<>(request.getNumberOfTags());
+        List<S7VarPayloadDataItem> payloadItems = new 
ArrayList<>(request.getNumberOfTags());
+
+        encodePlcStringWriteRequest((DefaultPlcWriteRequest) writeRequest,
+            parameterItems, payloadItems);
+
+        final int tpduId = tpduGenerator.getAndIncrement();
+        // If we've reached the max value for a 16 bit transaction identifier, 
reset back to 1
+        if (tpduGenerator.get() == 0xFFFF) {
+            tpduGenerator.set(1);
+        }
+
+        TPKTPacket tpktPacket = new TPKTPacket(
+            new COTPPacketData(
+                null,
+                new S7MessageRequest(tpduId,
+                    new S7ParameterWriteVarRequest(parameterItems),
+                    new S7PayloadWriteVarRequest(payloadItems)
+                ),
+                true,
+                (byte) tpduId
+            )
+        );
+
+        // Start a new request-transaction (Is ended in the response-handler)
+        RequestTransactionManager.RequestTransaction transaction = 
tm.startRequest();
+        transaction.submit(() -> context.sendRequest(tpktPacket)
+            .onTimeout(new TransactionErrorCallback<>(future, transaction))
+            .onError(new TransactionErrorCallback<>(future, transaction))
+            .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT)
+            .check(p -> p.getPayload() instanceof COTPPacketData)
+            .unwrap(p -> ((COTPPacketData) p.getPayload()))
+            .unwrap(COTPPacket::getPayload)
+            .check(p -> p.getTpduReference() == tpduId)
+            .handle(p -> {
+                try {
+                    future.complete(((PlcWriteResponse) decodeWriteResponse(p, 
writeRequest)));
+                } catch (PlcProtocolException e) {
+                    logger.warn("Error sending 'write' message: '{}'", 
e.getMessage(), e);
+                }
+                // Finish the request-transaction.
+                transaction.endRequest();
+            }));
+        return future;
+    }
 
     @Override
     public CompletableFuture<PlcSubscriptionResponse> 
subscribe(PlcSubscriptionRequest subscriptionRequest) {
@@ -1340,6 +1410,9 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
 //            });
     }
 
+    /*
+    *
+    */
     private void encodePlcClkRequest(DefaultPlcReadRequest request,
                                      List<S7ParameterUserDataItem> 
parameterItems,
                                      List<S7PayloadUserDataItem> payloadItems) 
{
@@ -1370,12 +1443,13 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
         payloadItems.add(payload);
     }
 
-
+    /*
+    *
+    */
     private void encodePlcClkSetRequest(DefaultPlcWriteRequest request,
                                         List<S7ParameterUserDataItem> 
parameterItems,
                                         List<S7PayloadUserDataItem> 
payloadItems) {
 
-
         S7ParameterUserDataItemCPUFunctions parameter = new 
S7ParameterUserDataItemCPUFunctions(
             (short) 0x11,   //Method
             (byte) 0x04,    //FunctionType
@@ -1404,6 +1478,207 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
     }
 
 
+    /*
+     *            +-------------------+
+     * Byte n     | Maximum length    | (intMaxChars)
+     *            +-------------------+
+     * Byte n+1   | Current Length    | (intActualChars)
+     *            +-------------------+
+     * Byte n+2   | 1st character     | \         \
+     *            +-------------------+  |         |
+     * Byte n+3   | 2st character     |  | Current |
+     *            +-------------------+   >        |
+     * Byte ...   | ...               |  | length  |  Maximum
+     *            +-------------------+  |          >
+     * Byte n+m+1 | mth character     | /          |  length
+     *            +-------------------+            |
+     * Byte ...   | ...               |            |
+     *            +-------------------+            |
+     * Byte ...   | ...               |           /
+     *            +-------------------+
+     * Reading text strings in two steps:
+     * 1. For the operation on texts, you must first evaluate the 
+     *    space created on DB of type STRING or WSTRING.
+     * 2. The first two bytes have the maximum number of characters (bytes) 
+     *    available to store text strings (intMaxChars) and the number of 
+     *    characters available (intActualChars).
+     * 3. In the specific case of reading, only the characters defined 
+     *    by "intActualChars" are recovered.
+     * TODO: Maximum waiting time managed by system variables.
+    */
+    private void encodePlcStringReadRequest(DefaultPlcReadRequest request,
+                                     List<S7ParameterReadVarRequest> 
parameterItems,
+                                     List<S7PayloadUserDataItem> payloadItems) 
{
+        
+        int intMaxChars = 0;
+        int intActualChars = 0;
+        
+        final S7StringTag tag = (S7StringTag) request.getTags().get(0);
+        
+        //Read the max length and actual size.
+        
+        final S7MessageRequest readRequest = new S7MessageRequest(1,new 
S7ParameterReadVarRequest(
+                List.of(new S7VarRequestParameterItemAddress(
+                        new S7AddressAny(
+                                TransportSize.BYTE,
+                                2,
+                                tag.getBlockNumber(),
+                                MemoryArea.DATA_BLOCKS,
+                                tag.getByteOffset(),
+                                tag.getBitOffset()
+                        ))
+            
+        )), null);
+                
+        CompletableFuture<S7Message> future = readInternal(readRequest);
+        
+        try {
+            S7Message get = future.get(2000, TimeUnit.MILLISECONDS);
+            final S7VarPayloadDataItem payload = 
(S7VarPayloadDataItem)((S7PayloadReadVarResponse) 
get.getPayload()).getItems().get(0);
+            //intMaxChars = Byte.toUnsignedInt(payload.getData()[0]);
+            intActualChars = Byte.toUnsignedInt(payload.getData()[1]);         
   
+        } catch (InterruptedException ex) {
+            logger.info(ex.getMessage());
+        } catch (ExecutionException ex) {
+            logger.info(ex.getMessage());
+        } catch (TimeoutException ex) {
+            logger.info(ex.getMessage());
+        }
+        
+        //Create the message structure for the user request.          
+        
+        S7ParameterReadVarRequest parameter = new S7ParameterReadVarRequest(
+                List.of(new S7VarRequestParameterItemAddress(
+                        new S7AddressAny(
+                                TransportSize.BYTE,
+                                intActualChars,
+                                tag.getBlockNumber(),
+                                MemoryArea.DATA_BLOCKS,
+                                tag.getByteOffset()+2,
+                                tag.getBitOffset()
+                        ))
+            
+        ));
+
+        parameterItems.clear();
+        parameterItems.add(parameter);
+
+        payloadItems.clear();
+
+    }
+
+
+    /*
+     *            +-------------------+
+     * Byte n     | Maximum length    | (intMaxChars)
+     *            +-------------------+
+     * Byte n+1   | Current Length    | (intActualChars)
+     *            +-------------------+
+     * Byte n+2   | 1st character     | \         \
+     *            +-------------------+  |         |
+     * Byte n+3   | 2st character     |  | Current |
+     *            +-------------------+   >        |
+     * Byte ...   | ...               |  | length  |  Maximum
+     *            +-------------------+  |          >
+     * Byte n+m+1 | mth character     | /          |  length
+     *            +-------------------+            |
+     * Byte ...   | ...               |            |
+     *            +-------------------+            |
+     * Byte ...   | ...               |           /
+     *            +-------------------+
+     * Reading text strings in two steps:
+     * 1. For the operation on texts, you must first evaluate the 
+     *    space created on DB of type STRING or WSTRING.
+     * 2. The first two bytes have the maximum number of characters (bytes) 
+     *    available to store text strings (intMaxChars) and the number of 
+     *    characters available (intActualChars).
+     * 3. In the specific case of write string, only the max characters 
defined 
+     *    by "intMaxChars" are writed.
+     * TODO: Maximum waiting time managed by system variables.
+    */
+    private void encodePlcStringWriteRequest(DefaultPlcWriteRequest request,
+                                        List<S7VarRequestParameterItem> 
parameterItems,
+                                        List<S7VarPayloadDataItem> 
payloadItems) {
+
+        int intMaxChars = 0;
+        int intActualChars = 0;
+        
+        final S7StringTag tag = (S7StringTag) request.getTags().get(0);
+        
+        //Read the max length and actual size.
+        
+        final S7MessageRequest readRequest = new S7MessageRequest(1,new 
S7ParameterReadVarRequest(
+                List.of(new S7VarRequestParameterItemAddress(
+                        new S7AddressAny(
+                                TransportSize.BYTE,
+                                2,
+                                tag.getBlockNumber(),
+                                MemoryArea.DATA_BLOCKS,
+                                tag.getByteOffset(),
+                                tag.getBitOffset()
+                        ))
+            
+        )), null);
+                
+        CompletableFuture<S7Message> future = readInternal(readRequest);
+        
+        try {
+            S7Message get = future.get(2000, TimeUnit.MILLISECONDS);
+            final S7VarPayloadDataItem payload = 
(S7VarPayloadDataItem)((S7PayloadReadVarResponse) 
get.getPayload()).getItems().get(0);
+            intMaxChars = Byte.toUnsignedInt(payload.getData()[0]); 
//payload.getData()[0] & 0xFF
+            intActualChars = Byte.toUnsignedInt(payload.getData()[1]);         
   
+        } catch (InterruptedException ex) {
+            logger.info(ex.getMessage());
+        } catch (ExecutionException ex) {
+            logger.info(ex.getMessage());
+        } catch (TimeoutException ex) {        
+            logger.info(ex.getMessage());
+        }
+
+        //Create the message structure for the user request.       
+        
+        parameterItems.clear();
+        payloadItems.clear();
+        
+        Iterator<String> iter = request.getTagNames().iterator();
+
+        String tagName;
+        PlcValue plcValue;
+        while (iter.hasNext()) {
+            tagName = iter.next();
+            final S7StringTag tagRef = (S7StringTag) request.getTag(tagName);
+            plcValue = request.getPlcValue(tagName);
+                        
+            //Check if String 
+            String strValue = plcValue.getString();
+            if (strValue.length() > intMaxChars) {
+                strValue = strValue.substring(0, intMaxChars);
+                plcValue = new PlcSTRING(strValue);
+            }
+            
+            S7Address s7Address = new S7AddressAny(
+                                        tagRef.getDataType().BYTE,
+                                        strValue.length() + 2,
+                                        tagRef.getBlockNumber(),
+                                        tagRef.getMemoryArea(),
+                                        tagRef.getByteOffset(),
+                                        tagRef.getBitOffset());
+            
+            parameterItems.add(new 
S7VarRequestParameterItemAddress(s7Address));            
+                                    
+            ByteBuffer byteBuffer = ByteBuffer.allocate(strValue.length() + 2);
+            byteBuffer.put((byte) intMaxChars);
+            byteBuffer.put((byte) strValue.length());
+            byteBuffer.put(strValue.getBytes());
+           
+            DataTransportSize transportSize = 
DataTransportSize.BYTE_WORD_DWORD;
+            
+            payloadItems.add(new 
S7VarPayloadDataItem(DataTransportErrorCode.OK, transportSize, 
byteBuffer.array()/*, hasNext*/));
+        }
+        
+    }    
+    
+    
     /**
      * This method is only called when there is no Response Handler.
      */
@@ -1622,7 +1897,17 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
         }
 
         //TODO: Reemsambling message.
-        if (responseMessage instanceof S7MessageUserData) {
+        if (responseMessage instanceof S7MessageResponseData) {
+            for (String tagName : plcReadRequest.getTagNames()) {        
+                if (plcReadRequest.getTag(tagName) instanceof S7StringTag) { 
+                    PlcValue plcValue = null;    
+                    PlcResponseCode responseCode = 
PlcResponseCode.INTERNAL_ERROR;
+                    List<PlcValue> plcValues = new LinkedList<>();
+                    ResponseItem<PlcValue> result = new 
ResponseItem<>(responseCode, plcValue);
+                    values.put(tagName, result);                     
+                }              
+            }            
+        } else if (responseMessage instanceof S7MessageUserData) {
 
             S7PayloadUserData payload = (S7PayloadUserData) 
responseMessage.getPayload();
             if (plcReadRequest.getNumberOfTags() != payload.getItems().size()) 
{
@@ -1725,15 +2010,18 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
                         dt.getMsec() * 1000000)));
                     plcValue = new PlcList(plcValues);
                 }
-
+                
                 ResponseItem<PlcValue> result = new 
ResponseItem<>(responseCode, plcValue);
                 values.put(tagName, result);
                 index++;
             }
+            
+
 
             return new DefaultPlcReadResponse(plcReadRequest, values);
 
         }
+        
 
         // In all other cases all went well.
         S7PayloadReadVarResponse payload = (S7PayloadReadVarResponse) 
responseMessage.getPayload();
@@ -1748,20 +2036,32 @@ public class S7ProtocolLogic extends 
Plc4xProtocolBase<TPKTPacket> {
 
         List<S7VarPayloadDataItem> payloadItems = payload.getItems();
         int index = 0;
+        PlcResponseCode responseCode = null;
+        PlcValue plcValue = null;
         for (String tagName : plcReadRequest.getTagNames()) {
-            S7Tag tag = (S7Tag) plcReadRequest.getTag(tagName);
-            S7VarPayloadDataItem payloadItem = payloadItems.get(index);
-
-            PlcResponseCode responseCode = 
decodeResponseCode(payloadItem.getReturnCode());
-            PlcValue plcValue = null;
-            ByteBuf data = Unpooled.wrappedBuffer(payloadItem.getData());
-            if (responseCode == PlcResponseCode.OK) {
-                try {
-                    plcValue = parsePlcValue(tag, data);
-                } catch (Exception e) {
-                    throw new PlcProtocolException("Error decoding PlcValue", 
e);
+            
+            if (plcReadRequest.getTag(tagName) instanceof S7StringTag) {
+                
+                final S7VarPayloadDataItem payloadItem = 
payloadItems.get(index);
+                responseCode = 
decodeResponseCode(payloadItem.getReturnCode());                
+                plcValue = new PlcSTRING(new String(payloadItem.getData(), 
StandardCharsets.UTF_8));
+                
+            } else {
+                S7Tag tag = (S7Tag) plcReadRequest.getTag(tagName);
+                S7VarPayloadDataItem payloadItem = payloadItems.get(index);
+
+                responseCode = decodeResponseCode(payloadItem.getReturnCode());
+                plcValue = null;
+                
+                ByteBuf data = Unpooled.wrappedBuffer(payloadItem.getData());
+                if (responseCode == PlcResponseCode.OK) {
+                    try {
+                        plcValue = parsePlcValue(tag, data);
+                    } catch (Exception e) {
+                        throw new PlcProtocolException("Error decoding 
PlcValue", e);
+                    }
                 }
-            }
+            };
             ResponseItem<PlcValue> result = new ResponseItem<>(responseCode, 
plcValue);
             values.put(tagName, result);
             index++;
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
index 2644737efb..c998d6f12f 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
@@ -84,7 +84,7 @@ public class S7ClkTag implements PlcTag {
 
     public static boolean matches(String address) {
         return CLK_ADDRESS_PATTERN.matcher(address).matches() ||
-            CLKF_ADDRESS_PATTERN.matcher(address).matches();
+                CLKF_ADDRESS_PATTERN.matcher(address).matches();
     }
 
     public static S7ClkTag of(String address) {
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
index 05b748df0b..4a43836a3a 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
@@ -27,14 +27,16 @@ public class S7PlcTagHandler implements PlcTagHandler {
 
     @Override
     public PlcTag parseTag(String tagAddress) {
-        if (S7Tag.matches(tagAddress)) {
-            return S7Tag.of(tagAddress);
+        if (S7StringTag.matches(tagAddress)) {
+            return S7StringTag.of(tagAddress);
         } else if (S7SubscriptionTag.matches(tagAddress)) {
             return S7SubscriptionTag.of(tagAddress);
         } else if (S7ClkTag.matches(tagAddress)) {
             return S7ClkTag.of(tagAddress);
         } else if (S7SzlTag.matches(tagAddress)) {
             return S7SzlTag.of(tagAddress);
+        } else if (S7Tag.matches(tagAddress)) {
+            return S7Tag.of(tagAddress);
         }
         throw new PlcInvalidTagException(tagAddress);
     }
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
index 23614677ec..4e81fb0da2 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
@@ -25,8 +25,35 @@ import 
org.apache.plc4x.java.spi.generation.SerializationException;
 import org.apache.plc4x.java.spi.generation.WriteBuffer;
 
 import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BIT_OFFSET;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BLOCK_NUMBER;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BYTE_OFFSET;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.DATA_TYPE;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.NUM_ELEMENTS;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.STRING_LENGTH;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.TRANSFER_SIZE_CODE;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.checkByteOffset;
+import static 
org.apache.plc4x.java.s7.readwrite.tag.S7Tag.checkDataBlockNumber;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.getSizeCode;
 
 public class S7StringTag extends S7Tag {
+    
+    private static final Pattern DATA_BLOCK_STRING =
+        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)?");
 
+
+    private static final Pattern DATA_BLOCK_STRING_SHORT =
+        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)?");
      
+    
+    private static final Pattern DATA_BLOCK_STRING_ADDRESS_PATTERN =
+        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
+    
+    private static final Pattern DATA_BLOCK_STRING_SHORT_PATTERN =
+        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
   
+    
+     
 
     private final int stringLength;
 
@@ -42,6 +69,14 @@ public class S7StringTag extends S7Tag {
         return stringLength;
     }
 
+    public static boolean matches(String address) {
+        return  DATA_BLOCK_STRING.matcher(address).matches() ||
+                DATA_BLOCK_STRING_SHORT.matcher(address).matches() ||
+                DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(address).matches() ||
+                DATA_BLOCK_STRING_SHORT_PATTERN.matcher(address).matches();
+    }    
+    
+    
     @Override
     public void serialize(WriteBuffer writeBuffer) throws 
SerializationException {
         writeBuffer.pushContext(getClass().getSimpleName());
@@ -64,5 +99,101 @@ public class S7StringTag extends S7Tag {
 
         writeBuffer.popContext(getClass().getSimpleName());
     }
+    
+    public static S7StringTag of(String address) {
+        Matcher matcher;
+        
+        if ((matcher = DATA_BLOCK_STRING_SHORT.matcher(address)).matches()) {
+            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+            int stringLength = -1;
+            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+            Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+            byte bitOffset = 0;
+            if (matcher.group(BIT_OFFSET) != null) {
+                bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+            } else if (dataType == TransportSize.BOOL) {
+                throw new PlcInvalidTagException("Expected bit offset for BOOL 
parameters.");
+            }
+            int numElements = 1;
+//            if (matcher.group(NUM_ELEMENTS) != null) {
+//                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+//            }
+
+            if ((transferSizeCode != null) && (dataType.getShortName() != 
transferSizeCode)) {
+                throw new PlcInvalidTagException("Transfer size code '" + 
transferSizeCode +
+                    "' doesn't match specified data type '" + dataType.name() 
+ "'");
+            }
+
+            return new S7StringTag(dataType, memoryArea, blockNumber, 
byteOffset, bitOffset, numElements, stringLength);
+                    
+        } else if ((matcher = DATA_BLOCK_STRING.matcher(address)).matches()) {
+            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+            int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+            Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+            byte bitOffset = 0;
+            if (matcher.group(BIT_OFFSET) != null) {
+                bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+            } else if (dataType == TransportSize.BOOL) {
+                throw new PlcInvalidTagException("Expected bit offset for BOOL 
parameters.");
+            }
+            int numElements = 1;
+            if (matcher.group(NUM_ELEMENTS) != null) {
+                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+            }
+
+            if ((transferSizeCode != null) && (dataType.getShortName() != 
transferSizeCode)) {
+                throw new PlcInvalidTagException("Transfer size code '" + 
transferSizeCode +
+                    "' doesn't match specified data type '" + dataType.name() 
+ "'");
+            }
+
+            return new S7StringTag(dataType, memoryArea, blockNumber, 
byteOffset, bitOffset, numElements, stringLength);
+                    
+        } else if ((matcher = 
DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(address)).matches()) {            
+            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+            int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+            Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+            byte bitOffset = 0;
+            if (matcher.group(BIT_OFFSET) != null) {
+                bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+            } else if (dataType == TransportSize.BOOL) {
+                throw new PlcInvalidTagException("Expected bit offset for BOOL 
parameters.");
+            }
+            int numElements = 1;
+            if (matcher.group(NUM_ELEMENTS) != null) {
+                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+            }
+
+            if ((transferSizeCode != null) && (dataType.getShortName() != 
transferSizeCode)) {
+                throw new PlcInvalidTagException("Transfer size code '" + 
transferSizeCode +
+                    "' doesn't match specified data type '" + dataType.name() 
+ "'");
+            }
+
+            return new S7StringTag(dataType, memoryArea, blockNumber, 
byteOffset, bitOffset, numElements, stringLength);
+        } else if ((matcher = 
DATA_BLOCK_STRING_SHORT_PATTERN.matcher(address)).matches()) {
+            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+            int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+            byte bitOffset = 0;
+            int numElements = 1;
+            if (matcher.group(NUM_ELEMENTS) != null) {
+                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+            }
+
+            return new S7StringTag(dataType, memoryArea, blockNumber,
+                byteOffset, bitOffset, numElements, stringLength);   
+        }
+        
+        return null;
+    }    
 
 }
diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
index 31ff6e3492..26c7917ac4 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
@@ -52,23 +52,19 @@ public class S7Tag implements PlcTag, Serializable {
     private static final Pattern DATA_BLOCK_SHORT_PATTERN =
         
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\\[(?<numElements>\\d+)])?");
 
-    private static final Pattern DATA_BLOCK_STRING_ADDRESS_PATTERN =
-        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
 
-    private static final Pattern DATA_BLOCK_STRING_SHORT_PATTERN =
-        
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
 
     private static final Pattern PLC_PROXY_ADDRESS_PATTERN =
         
Pattern.compile("[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}");
 
-    private static final String DATA_TYPE = "dataType";
-    private static final String STRING_LENGTH = "stringLength";
-    private static final String TRANSFER_SIZE_CODE = "transferSizeCode";
-    private static final String BLOCK_NUMBER = "blockNumber";
-    private static final String BYTE_OFFSET = "byteOffset";
-    private static final String BIT_OFFSET = "bitOffset";
-    private static final String NUM_ELEMENTS = "numElements";
-    private static final String MEMORY_AREA = "memoryArea";
+    protected static final String DATA_TYPE = "dataType";
+    protected static final String STRING_LENGTH = "stringLength";
+    protected static final String TRANSFER_SIZE_CODE = "transferSizeCode";
+    protected static final String BLOCK_NUMBER = "blockNumber";
+    protected static final String BYTE_OFFSET = "byteOffset";
+    protected static final String BIT_OFFSET = "bitOffset";
+    protected static final String NUM_ELEMENTS = "numElements";
+    protected static final String MEMORY_AREA = "memoryArea";
 
     private final TransportSize dataType;
     private final MemoryArea memoryArea;
@@ -136,8 +132,6 @@ public class S7Tag implements PlcTag, Serializable {
 
     public static boolean matches(String tagString) {
         return
-            DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString).matches() ||
-                DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString).matches() ||
                 DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString).matches() ||
                 DATA_BLOCK_SHORT_PATTERN.matcher(tagString).matches() ||
                 PLC_PROXY_ADDRESS_PATTERN.matcher(tagString).matches() ||
@@ -146,45 +140,46 @@ public class S7Tag implements PlcTag, Serializable {
 
     public static S7Tag of(String tagString) {
         Matcher matcher;
-        if ((matcher = 
DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString)).matches()) {
-            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
-            int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
-            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
-            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
-            Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
-            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
-            byte bitOffset = 0;
-            if (matcher.group(BIT_OFFSET) != null) {
-                bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
-            } else if (dataType == TransportSize.BOOL) {
-                throw new PlcInvalidTagException("Expected bit offset for BOOL 
parameters.");
-            }
-            int numElements = 1;
-            if (matcher.group(NUM_ELEMENTS) != null) {
-                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
-            }
-
-            if ((transferSizeCode != null) && (dataType.getShortName() != 
transferSizeCode)) {
-                throw new PlcInvalidTagException("Transfer size code '" + 
transferSizeCode +
-                    "' doesn't match specified data type '" + dataType.name() 
+ "'");
-            }
-
-            return new S7StringTag(dataType, memoryArea, blockNumber, 
byteOffset, bitOffset, numElements, stringLength);
-        } else if ((matcher = 
DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString)).matches()) {
-            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
-            int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
-            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
-            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
-            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
-            byte bitOffset = 0;
-            int numElements = 1;
-            if (matcher.group(NUM_ELEMENTS) != null) {
-                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
-            }
-
-            return new S7StringTag(dataType, memoryArea, blockNumber,
-                byteOffset, bitOffset, numElements, stringLength);
-        } else if ((matcher = 
DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString)).matches()) {
+//        if ((matcher = 
DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString)).matches()) {
+//            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+//            int stringLength = 
Integer.parseInt(matcher.group(STRING_LENGTH));
+//            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+//            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+//            Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+//            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+//            byte bitOffset = 0;
+//            if (matcher.group(BIT_OFFSET) != null) {
+//                bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+//            } else if (dataType == TransportSize.BOOL) {
+//                throw new PlcInvalidTagException("Expected bit offset for 
BOOL parameters.");
+//            }
+//            int numElements = 1;
+//            if (matcher.group(NUM_ELEMENTS) != null) {
+//                numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+//            }
+//
+//            if ((transferSizeCode != null) && (dataType.getShortName() != 
transferSizeCode)) {
+//                throw new PlcInvalidTagException("Transfer size code '" + 
transferSizeCode +
+//                    "' doesn't match specified data type '" + 
dataType.name() + "'");
+//            }
+//
+//            return new S7StringTag(dataType, memoryArea, blockNumber, 
byteOffset, bitOffset, numElements, stringLength);
+////        } else if ((matcher = 
DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString)).matches()) {
+////            TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
+////            int stringLength = 
Integer.parseInt(matcher.group(STRING_LENGTH));
+////            MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+////            int blockNumber = 
checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+////            int byteOffset = 
checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+////            byte bitOffset = 0;
+////            int numElements = 1;
+////            if (matcher.group(NUM_ELEMENTS) != null) {
+////                numElements = 
Integer.parseInt(matcher.group(NUM_ELEMENTS));
+////            }
+////
+////            return new S7StringTag(dataType, memoryArea, blockNumber,
+////                byteOffset, bitOffset, numElements, stringLength);
+//        } else 
+        if ((matcher = 
DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString)).matches()) {
             TransportSize dataType = 
TransportSize.valueOf(matcher.group(DATA_TYPE));
             MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
             Short transferSizeCode = 
getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
@@ -280,7 +275,7 @@ public class S7Tag implements PlcTag, Serializable {
      * @param blockNumber given DataBlockNumber
      * @return given blockNumber if Ok, throws PlcInvalidTagException otherwise
      */
-    private static int checkDataBlockNumber(int blockNumber) {
+    protected static int checkDataBlockNumber(int blockNumber) {
         // TODO: check the value or add reference - limit eventually depending 
on active S7 --> make a case selection
         if (blockNumber > 64000 || blockNumber < 1) {
             throw new PlcInvalidTagException("DataBlock numbers larger than 
64000 or smaller than 1 are not supported.");
@@ -294,7 +289,7 @@ public class S7Tag implements PlcTag, Serializable {
      * @param byteOffset given byteOffset
      * @return given byteOffset if Ok, throws PlcInvalidTagException otherwise
      */
-    private static int checkByteOffset(int byteOffset) {
+    protected static int checkByteOffset(int byteOffset) {
         // TODO: check the value or add reference
         if (byteOffset > 2097151 || byteOffset < 0) {
             throw new PlcInvalidTagException("ByteOffset must be smaller than 
2097151 and positive.");
diff --git 
a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java
 
b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java
new file mode 100644
index 0000000000..e86f296eff
--- /dev/null
+++ 
b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.examples.plc4j.s7event;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.commons.lang3.time.StopWatch;
+import org.apache.plc4x.java.DefaultPlcDriverManager;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.listener.ConnectionStateListener;
+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.types.PlcResponseCode;
+import org.apache.plc4x.java.s7.readwrite.protocol.S7HPlcConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+* 
+* Example of connection to a S7-400.
+* The connection is supervised.
+* Plc:              SIMATIC S7-400
+* Model:            CPU 417
+* Part number:      6ES7 417-4XT05-0AB0
+* Firmware version: 5.1.0
+* CP1: 6GK7 443-1EX11-0XE0
+* CP2: 6GK7 443-1EX20-0XB0
+* 
+* For the following program, the DB400 must be installed in the PLC, 
+* with the following chains and the indicated lengths.
+*
+* DB400
+* STRING001 - STRING[254]
+* STRING002 - STRING[172]
+* STRING003 - STRING[1]
+* STRING004 - STRING[0]
+* STRING005 - STRING[32]
+* STRING006 - STRING[64]
+* STRING007 - STRING[0]
+* STRING008 - STRING[1]
+* STRING009 - STRING[2]
+* STRING010 - STRING[3]
+* STRING011 - STRING[4]
+* STRING012 - STRING[5]
+* STRING013 - STRING[6]
+* STRING014 - STRING[7]
+* STRING015 - STRING[8]
+*/
+public class PlcReadWriteStrings implements ConnectionStateListener {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(PlcReadWriteStrings.class);   
+    private static final long DELAY = 1000L;
+    
+    private static String TEST_STRING00 = "";    
+    private static String TEST_STRING01 = "Y";    
+    private static String TEST_STRING02 = "YZ";     
+    private static String TEST_STRING08 = "01234567";
+    private static String TEST_STRING254 = 
+            "01234567890123456789012345678901234567890123456789"+    
+            "01234567890123456789012345678901234567890123456789"+
+            "01234567890123456789012345678901234567890123456789"+
+            "01234567890123456789012345678901234567890123456789"+
+            "01234567890123456789012345678901234567890123456789"+
+            "0123";
+    
+    private S7HPlcConnection connection = null; 
+    private AtomicBoolean isConnected = new AtomicBoolean(false);  
+    
+    private String[] tags = new String[]{"STRING007","STRING008","STRING009",
+                                         "STRING010","STRING011","STRING012",
+                                         "STRING013","STRING014","STRING015"}; 
   
+    
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+        
System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, 
"Debug");         
+        
+        PlcReadWriteStrings device = new PlcReadWriteStrings();
+        device.run();
+    }
+        
+    public void run() throws IOException {
+        logger.info("*****************************************************");
+        logger.info("* Example of connection and read to a Simatic S7-400H");  
      
+        logger.info("* Plc:              SIMATIC S7-400");
+        logger.info("* Model:            CPU 417");
+        logger.info("* Part number:      6ES7 417-4XT05-0AB0");
+        logger.info("* Firmware version: 5.1.0");        
+        logger.info("* CP1: 6GK7 443-1EX11-0XE0");   
+        logger.info("* CP2: 6GK7 443-1EX20-0XB0");   
+        logger.info("*");           
+        logger.info("* Note: . ");  
+        logger.info("*       . ");         
+        logger.info("*****************************************************"); 
+        
+        OpenConnection("s7://10.10.1.80/10.10.1.81?remote-rack=0&"
+                + "remote-slot=3&remote-rack2=0&remote-slot=4&"
+                + "controller-type=S7_400&read-timeout=16&"                
+                + "ping=true&ping-time=8&retry-time=3"); //(01)
+           
+        logger.info("*****************************************************"); 
+        logger.info("* 1. Once the connection is executed, it must read"); 
+        logger.info("*    the data contained in the address.");
+        logger.info("*    URL to:s7://10.10.1.80/10.10.1.81?remote-rack=0&");
+        logger.info("            remote-slot=3&remote-rack2=0&remote-slot=4&");
+        logger.info("            controller-type=S7_400&read-timeout=8&");
+        logger.info("            ping=true&ping-time=2&retry-time=3");
+        logger.info("*    Press [ENTER]");        
+        logger.info("*****************************************************"); 
+        
+        Read(); //(01.1)
+                 
+        logger.info("*****************************************************"); 
+        logger.info("* 2. Turn off/on PLC! This will cause the connection"); 
+        logger.info("*    handlers to be lost. ");       
+        logger.info("*    This simulates connection loss due to lack of ");
+        logger.info("*    traffic, which is handled by OS. ");
+        logger.info("*    When reading is executed, the driver must activate");
+        logger.info("*    the reconnection process internally.");
+        logger.info("*    In this operation the reading is lost, but ");
+        logger.info("*    the reconnection process begins.");
+        logger.info("*    Press [ENTER]");
+        logger.info("*****************************************************"); 
+        System.in.read();                      
+        
+        Write();
+        
+        logger.info("*****************************************************"); 
+        logger.info("* Write null string.. Clean the DB in ST7/TIA.");     
+        logger.info("* Press [ENTER]");        
+        logger.info("*****************************************************");  
 
+        System.in.read();          
+        SafeWrite(TEST_STRING00);
+        SafeRead(TEST_STRING00);
+ 
+        
+        logger.info("*****************************************************"); 
+        logger.info("* Write one character string.. Clean the DB in 
ST7/TIA.");    
+        logger.info("* Press [ENTER]");            
+        logger.info("*****************************************************");  
+        System.in.read();         
+        SafeWrite(TEST_STRING01);    
+        SafeRead(TEST_STRING01);        
+  
+                
+        logger.info("*****************************************************"); 
+        logger.info("* Write two character string.. Clean the DB in 
ST7/TIA.");    
+        logger.info("* Press [ENTER]");            
+        logger.info("*****************************************************");  
  
+        System.in.read();           
+        SafeWrite(TEST_STRING02);   
+        SafeRead(TEST_STRING02);         
+
+                
+        logger.info("*****************************************************"); 
+        logger.info("* Write eigth character string.. Clean the DB in 
ST7/TIA"); 
+        logger.info("* Press [ENTER]");            
+        logger.info("*****************************************************");  
+        System.in.read();         
+        SafeWrite(TEST_STRING08); 
+        SafeRead(TEST_STRING08);         
+  
+                
+        logger.info("*****************************************************"); 
+        logger.info("* Write 254 character string.. Clean the DB in ST7/TIA"); 
 
+        logger.info("* Press [ENTER]");            
+        logger.info("*****************************************************");  
+        System.in.read();         
+        SafeWrite(TEST_STRING254);    
+        SafeRead(TEST_STRING254);          
+  
+                
+        logger.info("*****************************************************"); 
+        logger.info("* 8. And we close the connection."); 
+        logger.info("*    Press [ENTER]");        
+        logger.info("*****************************************************");  
      
+        System.in.read();  
+        
+        CloseConnection(); //(08.1)        
+                
+    }    
+    
+    
+    
/***************************************************************************
+    * Under normal conditions, the driver expects you to have the PLC 
+    * connected to the network to start operations.
+    * If a connection to the PLC cannot be established, an exception of type 
+    * "PlcConnectionException" is generated, which must be handled by your 
+    * application. In this example it waits for a connection to exist.
+    * When you disconnect the "connection", the S7 driver will take care of 
the 
+    * connection and reconnection process if necessary.
+    * The internal wait time for the connection is one (01) second.
+    
***************************************************************************/
+    private void OpenConnection(String url) {
+        int retrys = 0;
+        StopWatch watch = new StopWatch();
+        watch.start(); 
+        while (null == connection) {
+            try {        
+                connection =(S7HPlcConnection) new DefaultPlcDriverManager().
+                        getConnection(url);
+                connection.addEventListener(this);
+                while (!connection.isConnected());
+                watch.stop();
+                
+                isConnected.set( connection.isConnected());
+                
+            logger.info("Time elapse for connection: {} in ms, with " +
+                        "rettrys: {}",watch.getTime(), retrys);
+            
+            } catch (PlcConnectionException ex) {
+                logger.info(ex.getMessage());
+                //Avoid excessive CPU consumption
+                try {
+                    TimeUnit.MILLISECONDS.sleep(DELAY);
+                } catch (InterruptedException ie) {
+                    Thread.currentThread().interrupt();
+                }                
+                 retrys++;
+            }
+        }
+        
+    }
+
+    
/***************************************************************************
+    * When the connection is closed, pending tasks and transactions are 
+    * completed.
+    * The rest of the work should be sent to the GC.
+    
***************************************************************************/
+    private void CloseConnection() {
+        if (null == connection) return;
+        isConnected.set(false);
+        try {
+            connection.close();
+            connection = null; //GC do you job!.
+            
+        } catch (PlcConnectionException ex) {
+            logger.info("CloseConnection: " + ex.getMessage());
+        }
+    }
+    
+    
/***************************************************************************
+    * The reading process is standard. In case of an exception, 
+    * the user must take the appropriate actions, but "do not close 
+    * the connection":
+    
***************************************************************************/    
+    private void Read() {
+        if (!isConnected.get()) return;
+        try {
+            final PlcReadRequest.Builder readrequest = 
connection.readRequestBuilder();  //(01)
+            readrequest.addTagAddress("TAG01", "%DB400.DBX0.0:STRING"); //(02) 
+            readrequest.addTagAddress("TAG06", "%DB400.DBX470.0:STRING"); 
//(02)             
+            readrequest.addTagAddress("TAG02", "%MB190:BYTE"); //(02) 
+            
+            final PlcReadRequest rr = readrequest.build(); //(03)
+            final PlcReadResponse response; //(04)            
+            response = rr.execute().get(); //(05)
+            
+            if (response.getResponseCode("TAG01") == PlcResponseCode.OK) { 
//(06)
+                logger.info("Value1: " + response.getString("TAG01"));
+                logger.info("Value2: " + response.getString("TAG06"));         
       
+                logger.info("Value3: " + response.getString("TAG02"));         
       
+            } else {
+                logger.info("Problem reading...");                
+            }              
+        } catch (Exception ex) { //(07)
+            logger.info("Read: " + ex.getMessage());
+        };          
+    }    
+    
+    
/***************************************************************************
+    * The reading process is standard. In case of an exception, 
+    * the user must take the appropriate actions, but "do not close 
+    * the connection":
+    
***************************************************************************/    
+    private void Write() {
+        if (!isConnected.get()) return;
+        try {
+            final PlcWriteRequest.Builder writeRequest = 
connection.writeRequestBuilder();  //(01)
+            writeRequest.addTagAddress("TAG01", 
"%DB400.DBX0.0:STRING",TEST_STRING254 ); //(02) 
+            writeRequest.addTagAddress("TAG06", 
"%DB400.DBX470.0:STRING",TEST_STRING254 ); //(02)           
+            writeRequest.addTagAddress("TAG08", 
"%DB400.DBX436.0:STRING",TEST_STRING254 ); //(02)              
+            
+            final PlcWriteRequest wr = writeRequest.build(); //(03)
+            final PlcWriteResponse response; //(04)            
+            response = wr.execute().get(); //(05)
+            
+            if (response.getResponseCode("TAG01") == PlcResponseCode.OK) { 
//(06)
+                logger.info("TAG01 Write sucefull...");
+            } else {
+                logger.info("TAG01 Problem reading...");                
+            }  
+
+            if (response.getResponseCode("TAG06") == PlcResponseCode.OK) { 
//(06)
+                logger.info("TAG06 Write sucefull...");
+            } else {
+                logger.info("TAG06 Problem reading...");                
+            }  
+            
+            if (response.getResponseCode("TAG08") == PlcResponseCode.OK) { 
//(06)
+                logger.info("TAG07 Write sucefull...");
+            } else {
+                logger.info("TAG07 Problem reading...");                
+            }              
+            
+        } catch (Exception ex) { //(07)
+            logger.info("Read: " + ex.getMessage());
+        };          
+    }     
+    
+    
/***************************************************************************
+    * Write the String "str" to the different test memory areas.
+    * No overlap of contents should be shown.
+    
***************************************************************************/    
+    private void SafeWrite(String str) {
+        if (!isConnected.get()) return;
+        try {
+            final PlcWriteRequest.Builder writeRequest = 
connection.writeRequestBuilder();  //(01)
+            writeRequest.addTagAddress(tags[0], "%DB400.DBX536.0:STRING",str); 
//(02) 
+            writeRequest.addTagAddress(tags[1], "%DB400.DBX538.0:STRING",str); 
//(02)  
+            writeRequest.addTagAddress(tags[2], "%DB400.DBX542.0:STRING",str); 
//(02) 
+            writeRequest.addTagAddress(tags[3], "%DB400.DBX546.0:STRING",str); 
//(02)  
+            writeRequest.addTagAddress(tags[4], "%DB400.DBX552.0:STRING",str); 
//(02) 
+            writeRequest.addTagAddress(tags[5], "%DB400.DBX558.0:STRING",str); 
//(02)  
+            writeRequest.addTagAddress(tags[6], "%DB400.DBX566.0:STRING",str); 
//(02) 
+            writeRequest.addTagAddress(tags[7], "%DB400.DBX574.0:STRING",str); 
//(02) 
+            writeRequest.addTagAddress(tags[8], "%DB400.DBX584.0:STRING",str); 
//(02)              
+            
+            final PlcWriteRequest wr = writeRequest.build(); //(03)
+            final PlcWriteResponse response; //(04)            
+            response = wr.execute().get(); //(05)
+            
+            for (String tag:tags) {
+                if (response.getResponseCode(tag) == PlcResponseCode.OK) //(06)
+                    logger.info(tag + " Write sucefull...");                
+            }
+            
+        } catch (Exception ex) { //(07)
+            logger.info("Read: " + ex.getMessage());
+        };          
+    }     
+    
+    
/***************************************************************************
+    * The reading process is standard. 
+    * Each "value" obtained from the PLC is compared with "str".
+    * If everything is fine, it should indicate a successful reading.
+    
***************************************************************************/    
+    private void SafeRead(String str) {
+        int index = 0;
+        int pos = 0;
+        if (!isConnected.get()) return;
+        try {
+            final PlcReadRequest.Builder readRequest = 
connection.readRequestBuilder();  //(01)
+            readRequest.addTagAddress(tags[0], "%DB400.DBX536.0:STRING"); 
//(02) 
+            readRequest.addTagAddress(tags[1], "%DB400.DBX538.0:STRING"); 
//(02)  
+            readRequest.addTagAddress(tags[2], "%DB400.DBX542.0:STRING"); 
//(02) 
+            readRequest.addTagAddress(tags[3], "%DB400.DBX546.0:STRING"); 
//(02)  
+            readRequest.addTagAddress(tags[4], "%DB400.DBX552.0:STRING"); 
//(02) 
+            readRequest.addTagAddress(tags[5], "%DB400.DBX558.0:STRING"); 
//(02)  
+            readRequest.addTagAddress(tags[6], "%DB400.DBX566.0:STRING"); 
//(02) 
+            readRequest.addTagAddress(tags[7], "%DB400.DBX574.0:STRING"); 
//(02) 
+            readRequest.addTagAddress(tags[8], "%DB400.DBX584.0:STRING"); 
//(02)  
+            
+            final PlcReadRequest rr = readRequest.build(); //(03)
+            final PlcReadResponse response; //(04)            
+            response = rr.execute().get(); //(05)
+            
+            
+            for (String tag:tags) {
+                if (response.getResponseCode(tag) == PlcResponseCode.OK){
+                    pos = (index <= str.length())?index:str.length();
+                    if (response.getString(tag).equals(str.substring(0, pos))){
+                        logger.info(tag + " Read sucefull...");      
+                    } else {
+                        logger.info(tag + ": " + response.getString(tag) + " : 
" + str.substring(0, index));     
+                    }
+                }
+                index++;
+            }            
+                        
+        } catch (Exception ex) { //(07)
+            logger.info("Read: " + ex.getMessage());
+        };          
+    }        
+    
+    
/***************************************************************************
+    * This method is called when the driver makes an internal TCP connection.
+    * The first connection of the driver does not generate this event.
+    * In the case of high availability systems, this signal should be used 
+    * to restart subscriptions to events, alarms, etc. 
+    
***************************************************************************/    
+    @Override
+    public void connected() {
+        logger.info("*****************************************************");  
       
+        logger.info("*************** Plc is connected. *******************");  
    
+        logger.info("*****************************************************"); 
+        isConnected.set(true);        
+    }
+
+    
/***************************************************************************
+    * This method is called when there is a physical disconnection of the 
driver
+    * Check the monitoring parameters given in the URL during connection.
+    
***************************************************************************/    
+    @Override
+    public void disconnected() {
+        logger.info("*****************************************************");  
       
+        logger.info("*************** Plc is disconnected. ****************");  
       
+        logger.info("*****************************************************");  
       
+        isConnected.set(false);
+    }    
+    
+    
+    
+}

Reply via email to