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 0379b241c9 fix: [Bug]: The block optimizer used in s7-light causes 
errors, if a tag references the same byte multiple times
0379b241c9 is described below

commit 0379b241c92879a763caf53345866736173856be
Author: Christofer Dutz <[email protected]>
AuthorDate: Sun Aug 10 11:26:43 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 ++++++++++++-----
 .../java/s7/readwrite/ManualS71200DriverTest2.java | 58 ++++++++++++++++++++++
 2 files changed, 91 insertions(+), 13 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 e6d0119b76..a17f8639a9 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
@@ -37,6 +37,7 @@ import 
org.apache.plc4x.java.spi.messages.utils.DefaultPlcTagItem;
 import org.apache.plc4x.java.spi.messages.utils.PlcResponseItem;
 import org.apache.plc4x.java.spi.messages.utils.PlcTagItem;
 import org.apache.plc4x.java.spi.values.DefaultPlcValueHandler;
+import org.apache.plc4x.java.spi.values.PlcBOOL;
 import org.apache.plc4x.java.spi.values.PlcNull;
 import org.apache.plc4x.java.spi.values.PlcRawByteArray;
 import org.slf4j.Logger;
@@ -391,25 +392,44 @@ public class S7BlockReadOptimizer extends S7Optimizer {
         try {
             int stringLength = (tag instanceof S7StringFixedLengthTag) ? 
((S7StringFixedLengthTag) tag).getStringLength() : 254;
             if (tag.getNumberOfElements() == 1) {
-                return DataItem.staticParse(readBuffer, 
tag.getDataType().getDataProtocolId(),
-                    s7DriverContext.getControllerType(), stringLength);
+                // If a boolean is being read, we need to manually parse it as 
we are reading bytes and not single bits.
+                if(tag.getDataType() == TransportSize.BOOL) {
+                    boolean bitValue = ((data[0] >> tag.getBitOffset()) & 
0x01) != 0;
+                    return PlcBOOL.of(bitValue);
+                } else {
+                    return DataItem.staticParse(readBuffer, 
tag.getDataType().getDataProtocolId(),
+                        s7DriverContext.getControllerType(), stringLength);
+                }
             } else {
                 // In case of reading an array of bytes, make use of our 
simpler PlcRawByteArray as the user is
                 // probably expecting to process the read raw data.
                 if(tag.getDataType() == TransportSize.BYTE) {
                     return new PlcRawByteArray(data);
                 } else {
-                    // Fetch all
-                    final PlcValue[] resultItems = IntStream.range(0, 
tag.getNumberOfElements()).mapToObj(i -> {
-                        try {
-                            return DataItem.staticParse(readBuffer, 
tag.getDataType().getDataProtocolId(),
-                                s7DriverContext.getControllerType(), 
stringLength);
-                        } catch (ParseException e) {
-                            logger.warn("Error parsing tag item of type: '{}' 
(at position {}})", tag.getDataType().name(), i, e);
-                        }
-                        return null;
-                    }).toArray(PlcValue[]::new);
-                    return DefaultPlcValueHandler.of(tag, resultItems);
+                    // If a boolean is being read, we need to manually parse 
it as we are reading bytes and not single bits.
+                    if(tag.getDataType() == TransportSize.BOOL) {
+                        int rootBitOffset = tag.getBitOffset();
+                        final PlcValue[] resultItems = IntStream.range(0, 
tag.getNumberOfElements()).mapToObj(i -> {
+                            int bitOffset = rootBitOffset + i;
+                            int byteOffset = bitOffset / 8;
+                            bitOffset = bitOffset % 8;
+                            boolean bitValue = ((data[byteOffset] >> 
bitOffset) & 0x01) != 0;
+                            return PlcBOOL.of(bitValue);
+                        }).toArray(PlcValue[]::new);
+                        return DefaultPlcValueHandler.of(tag, resultItems);
+                    } else {
+                        // Fetch all
+                        final PlcValue[] resultItems = IntStream.range(0, 
tag.getNumberOfElements()).mapToObj(i -> {
+                            try {
+                                return DataItem.staticParse(readBuffer, 
tag.getDataType().getDataProtocolId(),
+                                    s7DriverContext.getControllerType(), 
stringLength);
+                            } catch (ParseException e) {
+                                logger.warn("Error parsing tag item of type: 
'{}' (at position {}})", tag.getDataType().name(), i, e);
+                            }
+                            return null;
+                        }).toArray(PlcValue[]::new);
+                        return DefaultPlcValueHandler.of(tag, resultItems);
+                    }
                 }
             }
         } catch (ParseException e) {
diff --git 
a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71200DriverTest2.java
 
b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71200DriverTest2.java
new file mode 100644
index 0000000000..acd2347bbe
--- /dev/null
+++ 
b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS71200DriverTest2.java
@@ -0,0 +1,58 @@
+/*
+ * 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.java.s7.readwrite;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.spi.values.*;
+import org.apache.plc4x.test.manual.ManualTest;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ManualS71200DriverTest2 extends ManualTest {
+
+    /*
+     * Test program code on the PLC with the test-data.
+     * Reading the states of the 5 input booleans. Used to test how multiple 
bits located in one byte are handled.
+     */
+
+    public ManualS71200DriverTest2(String connectionString) {
+        super(connectionString, true, true, true, true, 100);
+    }
+
+    public static void main(String[] args) throws Exception {
+        ManualS71200DriverTest2 test = new 
ManualS71200DriverTest2("s7://192.168.23.30");
+        test.addTestCase("%I0.0:BOOL", new PlcBOOL(false));
+        test.addTestCase("%I0.1:BOOL", new PlcBOOL(true));
+        test.addTestCase("%I0.2:BOOL", new PlcBOOL(true));
+        test.addTestCase("%I0.3:BOOL", new PlcBOOL(false));
+        test.addTestCase("%I0.4:BOOL", new PlcBOOL(false));
+        //test.addTestCase("%I0.0:BOOL[5]", new PlcList(new 
ArrayList<>(List.of(new PlcBOOL(false), new PlcBOOL(true), new PlcBOOL(true), 
new PlcBOOL(false), new PlcBOOL(false)))));
+
+        long start = System.currentTimeMillis();
+        test.run();
+        long end = System.currentTimeMillis();
+        System.out.printf("Finished in %d ms", end - start);
+    }
+
+}

Reply via email to