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

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


The following commit(s) were added to refs/heads/develop by this push:
     new b4782c0b3a fix: [Bug]: The block optimizer used in s7-light causes 
errors, if a tag references the same byte multiple times
b4782c0b3a is described below

commit b4782c0b3a76010c4316c106391478caac310acd
Author: Christofer Dutz <christofer.d...@c-ware.de>
AuthorDate: Sun Aug 10 17:11:21 2025 +0200

    fix: [Bug]: The block optimizer used in s7-light causes errors, if a tag 
references the same byte multiple times
    
    closes: #2213
---
 .../readwrite/optimizer/S7BlockReadOptimizer.java  | 46 +++++++++++++---------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7light/readwrite/optimizer/S7BlockReadOptimizer.java
 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7light/readwrite/optimizer/S7BlockReadOptimizer.java
index a17f8639a9..41422a2ad6 100644
--- 
a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7light/readwrite/optimizer/S7BlockReadOptimizer.java
+++ 
b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7light/readwrite/optimizer/S7BlockReadOptimizer.java
@@ -69,7 +69,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
         }
 
         // Sort the tags by area
-        // (We can only read multiple tags in one byte array, if they are 
located in the same area)
+        // (We can only read multiple tags in one byte array if they are 
located in the same area)
         Map<String, Map<PlcTag, String>> sortedTagsPerArea = new HashMap<>();
         for (String tagName : readRequest.getTagNames()) {
             PlcTag tag = readRequest.getTag(tagName);
@@ -86,7 +86,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
             } else if(tag instanceof S7Tag) {
                 S7Tag s7Tag = (S7Tag) tag;
                 MemoryArea memoryArea = s7Tag.getMemoryArea();
-                // When reading DATA_BLOCKS we need to also use the block 
number.
+                // When reading DATA_BLOCKS, we need to also use the block 
number.
                 String areaName = memoryArea.getShortName();
                 if(memoryArea ==  MemoryArea.DATA_BLOCKS) {
                     areaName += s7Tag.getBlockNumber();
@@ -123,7 +123,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                     // TODO: Implement the size
                     optimizedTagMap.put(new TagNameSize(tagList.get(plcTag), 
0), new DefaultPlcTagItem<>(plcTag));
                 }
-                // Var-length strings, are a performance nightmare. Trying to 
optimize reading them is probably not
+                // Var-length strings are a performance nightmare. Trying to 
optimize reading them is probably not
                 // worth the effort. For now, we simply handle them as 
un-chunked tags.
                 else if(plcTag instanceof S7StringVarLengthTag) {
                     // A var-length string tag simply reads 2 or 4 bytes.
@@ -136,8 +136,11 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                 else if (plcTag instanceof S7Tag) {
                     S7Tag s7Tag = (S7Tag) plcTag;
 
-                    int curTagSize = s7Tag.getDataType().getSizeInBytes() * 
s7Tag.getNumberOfElements();
-                    // In case of fixed length strings, a string starts with 
two bytes: max length,
+                    // If the dataType is BOOL, the size in bytes needs to be 
calculated differently.
+                    // Especially if it's more than one element.
+                    int curTagSize = s7Tag.getDataType() == TransportSize.BOOL 
? (s7Tag.getNumberOfElements() + 7) / 8 :
+                        s7Tag.getDataType().getSizeInBytes() * 
s7Tag.getNumberOfElements();
+                    // In the case of fixed length strings, a string starts 
with two bytes: max length,
                     // actual length and then the string bytes after that.
                     if(s7Tag instanceof S7StringFixedLengthTag) {
                         S7StringFixedLengthTag stringFixedLengthTag = 
(S7StringFixedLengthTag) s7Tag;
@@ -145,14 +148,14 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                         curTagSize = ((2 * bytesPerChar) + 
(stringFixedLengthTag.getStringLength() * bytesPerChar)) * 
s7Tag.getNumberOfElements();
                     }
 
-                    // If this is the first tag, use that as starting point.
+                    // If this is the first tag, use that as a starting point.
                     if(currentMemoryArea == null) {
                         currentMemoryArea = s7Tag.getMemoryArea();
                         currentDataBlockNumber = s7Tag.getBlockNumber();
                         currentChunkStartByteOffset = s7Tag.getByteOffset();
                         currentChunkEndByteOffset = s7Tag.getByteOffset() + 
curTagSize;
                     }
-                    // If the next tag would be more bytes away than a s7 
address item requires, it's cheaper to
+                    // If the next tag is more bytes away than a s7 address 
item requires, it cost fewer resources to
                     // split up into multiple items.
                     else if(currentChunkEndByteOffset + S7_ADDRESS_ANY_SIZE < 
s7Tag.getByteOffset()) {
                         // Save the current chunk.
@@ -170,7 +173,8 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                     }
                     // Otherwise extend the array size to include this tag.
                     else {
-                        currentChunkEndByteOffset = s7Tag.getByteOffset() + 
curTagSize;
+                        // Check if adding this tag would increase the size of 
the array.
+                        currentChunkEndByteOffset = 
Math.max(currentChunkEndByteOffset, s7Tag.getByteOffset() + curTagSize);
                     }
 
                     // Add the tag to the list of tags for the current chunk.
@@ -188,7 +192,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
         }
 
         // Go through all chunks. If there are ones larger than the max PDU 
size, split them up into
-        // multiple tags, that utilize the packets to the maximum.
+        // multiple tags that use the packets to the maximum.
         final int maxRequestSize = ((S7DriverContext) 
driverContext).getPduSize() - (EMPTY_READ_RESPONSE_SIZE + 4);
         Map<TagNameSize, PlcTagItem<PlcTag>> optimizedTagMap2 = new 
TreeMap<>();
         for (TagNameSize tagNameSize : optimizedTagMap.keySet()) {
@@ -225,17 +229,17 @@ public class S7BlockReadOptimizer extends S7Optimizer {
             }
         }
 
-        // Using the First Fit Decreasing (FFD) bin-packing algorithm try to 
find the ideal
-        // packing for utilizing request sizes.
+        // Using the First Fit Decreasing (FFD) bin-packing algorithm, try to 
find the ideal
+        // packing for using request sizes.
         // 1. Assign a size to each tag
         // 2. Sort the tags by size (biggest first)
-        // 3. Repeat this, till all tags are consumed
+        // 3. Repeat this till all tags are consumed
         //      1. Take the first packet of the list
         //      2. If the tag itself exceeds the max request size, keep on 
splitting it into chunks until
-        //         the rest would fit into a request. Then proceed with the 
rest as if it was a normal tag
+        //         the rest fit into a request. Then proceed with the rest as 
if it was a normal tag
         //      2. Go through the existing list of requests and check if the 
current tag would fit
         //          1. If it fits, add it to the request
-        //          2. If it doesn't fit go to the next request and check
+        //          2. If it doesn't fit, go to the next request and check
         //          3. If you reach the end, and it didn't fit any of the 
previous requests, add a new one
         LinkedHashMap<String, PlcTagItem<PlcTag>> executableTagMap = new 
LinkedHashMap<>();
         for (TagNameSize tagNameSize : optimizedTagMap2.keySet()) {
@@ -266,7 +270,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
         // Have the upstream optimizer handle its thing.
         PlcReadResponse rawReadResponse = super.processReadResponses(new 
DefaultPlcReadRequest(((DefaultPlcReadRequest) readRequest).getReader(), tags), 
readResponses, driverContext);
 
-        // Merge together split-up chunks.
+        // Merge split-up chunks.
         LinkedHashMap<String, PlcTagItem<PlcTag>> mergedTagItems = new 
LinkedHashMap<>();
         Map<String, PlcResponseItem<PlcValue>> mergedValues = new 
LinkedHashMap<>();
         for (String tagName : rawReadResponse.getTagNames()) {
@@ -308,7 +312,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                     mergedValues.put(tagBaseName, new 
DefaultPlcResponseItem<>(PlcResponseCode.OK, new PlcRawByteArray(chunkData)));
                 }
             }
-            // All others are just un-split chunks
+            // All others are just unsplit chunks
             else {
                 PlcResponseCode responseCode = 
rawReadResponse.getResponseCode(tagName);
                 PlcValue plcValue = rawReadResponse.getPlcValue(tagName);
@@ -318,7 +322,7 @@ public class S7BlockReadOptimizer extends S7Optimizer {
         }
         PlcReadResponse mergedReadResponse = new DefaultPlcReadResponse(new 
DefaultPlcReadRequest(((DefaultPlcReadRequest)rawReadResponse.getRequest()).getReader(),
 mergedTagItems), mergedValues);
 
-        // If a Tag is a normal tag, just copy it over. However, if it's a 
S7TagChunk, process it.
+        // If a Tag is a normal tag, just copy it over. However, if it's an 
S7TagChunk, process it.
         Map<String, PlcResponseItem<PlcValue>> values = new HashMap<>();
         for (String tagName : mergedReadResponse.getTagNames()) {
             PlcResponseCode responseCode = 
mergedReadResponse.getResponseCode(tagName);
@@ -342,7 +346,8 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                 S7Tag s7Tag = (S7Tag) plcTag;
                 String curTagName = s7TagChunk.getChunkTags().get(plcTag);
                 int curTagStartPosition = s7Tag.getByteOffset() - 
chunkByteOffset;
-                int curTagDataSize = s7Tag.getDataType().getSizeInBytes() * 
s7Tag.getNumberOfElements();
+                int curTagDataSize = s7Tag.getDataType() == TransportSize.BOOL 
? (s7Tag.getNumberOfElements() + 7) / 8 :
+                    s7Tag.getDataType().getSizeInBytes() * 
s7Tag.getNumberOfElements();
                 if(s7Tag instanceof S7StringFixedLengthTag) {
                     S7StringFixedLengthTag s7StringFixedLengthTag = 
(S7StringFixedLengthTag) s7Tag;
                     if(s7Tag.getDataType() == TransportSize.WSTRING) {
@@ -372,13 +377,16 @@ public class S7BlockReadOptimizer extends S7Optimizer {
                 }
                 return s7Tag1.getSzlId() - s7Tag2.getSzlId();
             } else if (tag1 instanceof S7ClkTag) {
-                // Technically CLK tags should be identical as there's
+                // Technically, CLK tags should be identical as there's
                 // only one address for reading the PLC clock information.
                 return 0;
             } else if (tag1 instanceof S7Tag) {
                 S7Tag s7Tag1 = (S7Tag) tag1;
                 S7Tag s7Tag2 = (S7Tag) tag2;
                 if (s7Tag1.getByteOffset() == s7Tag2.getByteOffset()) {
+                    if (s7Tag1.getBitOffset() == s7Tag2.getBitOffset()) {
+                        return s7Tag1.getNumberOfElements() - 
s7Tag2.getNumberOfElements();
+                    }
                     return s7Tag1.getBitOffset() - s7Tag2.getBitOffset();
                 }
                 return s7Tag1.getByteOffset() - s7Tag2.getByteOffset();

Reply via email to