From 692931e65fece7199465dbbb39fb5b95acc09415 Mon Sep 17 00:00:00 2001 From: Ismo Leszczynski Date: Wed, 9 Apr 2025 14:29:40 +0300 Subject: [PATCH 1/4] Update ModbusOptimizer.java Fix Discrete Input handling when processing response --- .../plc4x/java/modbus/base/optimizer/ModbusOptimizer.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java index db838c6a0b0..c604eed96e9 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java @@ -192,7 +192,7 @@ protected PlcReadResponse processReadResponses(PlcReadRequest readRequest, Map

Date: Wed, 16 Apr 2025 12:54:28 +0300 Subject: [PATCH 2/4] Update ModbusOptimizer.java Fixed endianness resolution to check modbusTag overrides --- .../plc4x/java/modbus/base/optimizer/ModbusOptimizer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java index c604eed96e9..0bde206c48a 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java @@ -228,12 +228,14 @@ else if (response.matchesRegister(modbusTag)) { break; } + var byteOrder = modbusTag.getByteOrder() != null ? modbusTag.getByteOrder() : modbusContext.getByteOrder(); + byte[] responseData = response.getResponseDataForTag(modbusTag); - ReadBuffer readBuffer = getReadBuffer(responseData, modbusContext.getByteOrder()); + ReadBuffer readBuffer = getReadBuffer(responseData, byteOrder); try { PlcValue plcValue = DataItem.staticParse(readBuffer, modbusTag.getDataType(), modbusTag.getNumberOfElements(), - modbusContext.getByteOrder() == ModbusByteOrder.BIG_ENDIAN); + byteOrder == ModbusByteOrder.BIG_ENDIAN); values.put(tagName, new DefaultPlcResponseItem<>(PlcResponseCode.OK, plcValue)); } catch (ParseException e) { values.put(tagName, new DefaultPlcResponseItem<>(PlcResponseCode.INTERNAL_ERROR, null)); From 66467ef22a3b78f6b928cd7c2c7eff6d0c233904 Mon Sep 17 00:00:00 2001 From: Ismo Leszczynski Date: Wed, 23 Jul 2025 12:48:18 +0300 Subject: [PATCH 3/4] fix(modbus): Modbus Coil/DI array fix Fixed response handling for Modbus Coil and Discrete Input arrays --- .../base/optimizer/ModbusOptimizer.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java index 0bde206c48a..e4ecf75726b 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java @@ -51,6 +51,7 @@ import org.apache.plc4x.java.spi.messages.utils.PlcTagItem; import org.apache.plc4x.java.spi.optimizer.SingleTagOptimizer; import org.apache.plc4x.java.spi.values.PlcBOOL; +import org.apache.plc4x.java.spi.values.PlcList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -208,11 +209,25 @@ protected PlcReadResponse processReadResponses(PlcReadRequest readRequest, Map

(PlcResponseCode.OK, new PlcBOOL(isBitSet))); + + // Check if we're dealing with an array of Coils or Discrete Inputs + if (modbusTag.getNumberOfElements() > 1) { + PlcList bitValues = new PlcList(); + for (int i = 0; i < modbusTag.getNumberOfElements(); i++) { + int bitPosition = modbusTag.getAddress() - response.startingAddress + i; + int bytePosition = bitPosition / 8; + int bitPositionInByte = bitPosition % 8; + boolean isBitSet = (responseData[bytePosition] & (1 << bitPositionInByte)) != 0; + bitValues.add(new PlcBOOL(isBitSet)); + } + values.put(tagName, new DefaultPlcResponseItem<>(PlcResponseCode.OK, bitValues)); + } else { + int bitPosition = modbusTag.getAddress() - response.startingAddress; + int bytePosition = bitPosition / 8; + int bitPositionInByte = bitPosition % 8; + boolean isBitSet = (responseData[bytePosition] & (1 << bitPositionInByte)) != 0; + values.put(tagName, new DefaultPlcResponseItem<>(PlcResponseCode.OK, new PlcBOOL(isBitSet))); + } break; } } From cdebad657006d633c7fa5599361f56f6e7f35049 Mon Sep 17 00:00:00 2001 From: Ismo Leszczynski Date: Wed, 23 Jul 2025 12:51:32 +0300 Subject: [PATCH 4/4] feat(modbus): Word Swap support Added support for Modbus Word Swapping --- .../base/optimizer/ModbusOptimizer.java | 26 +++++++++++++++++++ .../base/protocol/ModbusProtocolLogic.java | 14 ++++++++++ .../java/modbus/types/ModbusByteOrder.java | 14 +++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java index e4ecf75726b..f09ff963e08 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/optimizer/ModbusOptimizer.java @@ -451,6 +451,32 @@ private ReadBuffer getReadBuffer(byte[] data, ModbusByteOrder byteOrder) { byte[] reordered = ModbusProtocolLogic.byteSwap(data); return new ReadBufferByteBased(reordered, ByteOrder.LITTLE_ENDIAN); } + case BIG_ENDIAN_WORD_SWAP: { + // [3, 4, 1, 2] + // [3, 4, 1, 2, 7, 8, 5, 6] + byte[] reordered = ModbusProtocolLogic.wordSwap(data); + return new ReadBufferByteBased(reordered, ByteOrder.BIG_ENDIAN); + } + case LITTLE_ENDIAN_WORD_SWAP: { + // [2, 1, 4, 3] + // [6, 5, 8, 7, 2, 1, 4, 3] + byte[] reordered = ModbusProtocolLogic.wordSwap(data); + return new ReadBufferByteBased(reordered, ByteOrder.LITTLE_ENDIAN); + } + case BIG_ENDIAN_WORD_SWAP_BYTE_SWAP: { + // [4, 3, 2, 1] + // [4, 3, 2, 1, 8, 7, 6, 5] + byte[] reordered = ModbusProtocolLogic.byteSwap(data); + reordered = ModbusProtocolLogic.wordSwap(reordered); + return new ReadBufferByteBased(reordered, ByteOrder.BIG_ENDIAN); + } + case LITTLE_ENDIAN_WORD_SWAP_BYTE_SWAP: { + // [1, 2, 3, 4] + // [5, 6, 7, 8, 1, 2, 3, 4] + byte[] reordered = ModbusProtocolLogic.byteSwap(data); + reordered = ModbusProtocolLogic.wordSwap(reordered); + return new ReadBufferByteBased(reordered, ByteOrder.LITTLE_ENDIAN); + } default: // 16909060 // [1, 2, 3, 4] diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java index 12a185dcfc2..74b79121828 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/protocol/ModbusProtocolLogic.java @@ -412,4 +412,18 @@ public static byte[] byteSwap(byte[] in) { return out; } + public static byte[] wordSwap(byte[] in) { + if (in.length % 2 != 0) { + throw new PlcRuntimeException("Input byte array length must be a multiple of 2 for word swapping."); + } + byte[] out = new byte[in.length]; + for (int i = 0; i < in.length; i += 4) { + out[i] = in[i + 2]; + out[i + 1] = in[i + 3]; + out[i + 2] = in[i]; + out[i + 3] = in[i + 1]; + } + return out; + } + } diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/types/ModbusByteOrder.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/types/ModbusByteOrder.java index 98415071fc5..9f94321bcc6 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/types/ModbusByteOrder.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/types/ModbusByteOrder.java @@ -30,5 +30,17 @@ public enum ModbusByteOrder { BIG_ENDIAN_BYTE_SWAP, // [3, 4, 1, 2] // [7, 8, 5, 6, 3, 4, 1, 2] - LITTLE_ENDIAN_BYTE_SWAP + LITTLE_ENDIAN_BYTE_SWAP, + // [3, 4, 1, 2] + // [3, 4, 1, 2, 7, 8, 5, 6] + BIG_ENDIAN_WORD_SWAP, + // [2, 1, 4, 3] + // [6, 5, 8, 7, 2, 1, 4, 3] + LITTLE_ENDIAN_WORD_SWAP, + // [4, 3, 2, 1] + // [4, 3, 2, 1, 8, 7, 6, 5] + BIG_ENDIAN_WORD_SWAP_BYTE_SWAP, + // [1, 2, 3, 4] + // [5, 6, 7, 8, 1, 2, 3, 4] + LITTLE_ENDIAN_WORD_SWAP_BYTE_SWAP, }