You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2024/06/21 14:31:56 UTC
(plc4x) branch develop updated: feat: Added support for modbus encodings of "LITTLE_ENDIAN_BYTE_SWAP" and "BIG_ENDIAN_BYTE_SWAP" as well as support for overriding the byte-order on a per-tag basis.
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 fecd23ece9 feat: Added support for modbus encodings of "LITTLE_ENDIAN_BYTE_SWAP" and "BIG_ENDIAN_BYTE_SWAP" as well as support for overriding the byte-order on a per-tag basis.
fecd23ece9 is described below
commit fecd23ece9008b4f32e88e88a0ee56aa32b2ab45
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Fri Jun 21 16:31:48 2024 +0200
feat: Added support for modbus encodings of "LITTLE_ENDIAN_BYTE_SWAP" and "BIG_ENDIAN_BYTE_SWAP" as well as support for overriding the byte-order on a per-tag basis.
---
.../all/src/site/generated/modbus-ascii.adoc | 3 +
.../drivers/all/src/site/generated/modbus-rtu.adoc | 3 +
.../drivers/all/src/site/generated/modbus-tcp.adoc | 3 +
.../ascii/config/ModbusAsciiConfiguration.java | 12 +-
.../ascii/protocol/ModbusAsciiProtocolLogic.java | 7 +-
.../modbus/base/protocol/ModbusProtocolLogic.java | 132 +++++++++++++++++----
.../plc4x/java/modbus/base/tag/ModbusTag.java | 11 ++
.../modbus/rtu/config/ModbusRtuConfiguration.java | 12 +-
.../rtu/protocol/ModbusRtuProtocolLogic.java | 7 +-
.../modbus/tcp/config/ModbusTcpConfiguration.java | 12 +-
.../tcp/protocol/ModbusTcpProtocolLogic.java | 7 +-
.../plc4x/java/modbus/types/ModbusByteOrder.java | 17 +--
.../plc4x/java/modbus/utils/ByteOrderUtils.java | 101 ----------------
.../apache/plc4x/java/modbus/ManualDriverTest.java | 67 +++++++++++
.../java/modbus/ManualModbusTCPDriverTest.java | 2 +-
.../java/modbus/utils/ByteOrderUtilsTest.java | 79 ------------
src/site/asciidoc/users/protocols/modbus.adoc | 8 +-
17 files changed, 254 insertions(+), 229 deletions(-)
diff --git a/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc b/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
index 99f531c3cd..7d3ec89ad2 100644
--- a/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
+++ b/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
@@ -43,6 +43,9 @@
Allowed values are: +
- BIG_ENDIAN +
- LITTLE_ENDIAN +
+ - BIG_ENDIAN_BYTE_SWAP +
+ - LITTLE_ENDIAN_BYTE_SWAP +
+ +
*Since: 0.13.0*
5+|Transport config options:
5+|
diff --git a/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc b/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
index a526d0e294..83f9811d0d 100644
--- a/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
+++ b/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
@@ -44,6 +44,9 @@
Allowed values are: +
- BIG_ENDIAN +
- LITTLE_ENDIAN +
+ - BIG_ENDIAN_BYTE_SWAP +
+ - LITTLE_ENDIAN_BYTE_SWAP +
+ +
*Since: 0.13.0*
5+|Transport config options:
5+|
diff --git a/plc4j/drivers/all/src/site/generated/modbus-tcp.adoc b/plc4j/drivers/all/src/site/generated/modbus-tcp.adoc
index 6d1417db12..94abe6eb55 100644
--- a/plc4j/drivers/all/src/site/generated/modbus-tcp.adoc
+++ b/plc4j/drivers/all/src/site/generated/modbus-tcp.adoc
@@ -43,6 +43,9 @@
Allowed values are: +
- BIG_ENDIAN +
- LITTLE_ENDIAN +
+ - BIG_ENDIAN_BYTE_SWAP +
+ - LITTLE_ENDIAN_BYTE_SWAP +
+ +
*Since: 0.13.0*
5+|Transport config options:
5+|
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/config/ModbusAsciiConfiguration.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/config/ModbusAsciiConfiguration.java
index 93a50ceb3b..60ddec578a 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/config/ModbusAsciiConfiguration.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/config/ModbusAsciiConfiguration.java
@@ -18,13 +18,13 @@
*/
package org.apache.plc4x.java.modbus.ascii.config;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.configuration.PlcConnectionConfiguration;
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.Description;
import org.apache.plc4x.java.spi.configuration.annotations.Since;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.StringDefaultValue;
-import org.apache.plc4x.java.spi.generation.ByteOrder;
public class ModbusAsciiConfiguration implements PlcConnectionConfiguration {
@@ -43,9 +43,11 @@ public class ModbusAsciiConfiguration implements PlcConnectionConfiguration {
@Description("Default encoding used for transporting register values (Defaults to BIG_ENDIAN).\n" +
"Allowed values are: \n" +
" - BIG_ENDIAN\n" +
- " - LITTLE_ENDIAN")
+ " - LITTLE_ENDIAN\n" +
+ " - BIG_ENDIAN_BYTE_SWAP\n" +
+ " - LITTLE_ENDIAN_BYTE_SWAP\n")
@Since("0.13.0")
- private ByteOrder defaultPayloadByteOrder;
+ private ModbusByteOrder defaultPayloadByteOrder;
public int getRequestTimeout() {
return requestTimeout;
@@ -63,11 +65,11 @@ public class ModbusAsciiConfiguration implements PlcConnectionConfiguration {
this.defaultUnitIdentifier = defaultUnitIdentifier;
}
- public ByteOrder getDefaultPayloadByteOrder() {
+ public ModbusByteOrder getDefaultPayloadByteOrder() {
return defaultPayloadByteOrder;
}
- public void setDefaultPayloadByteOrder(ByteOrder defaultPayloadByteOrder) {
+ public void setDefaultPayloadByteOrder(ModbusByteOrder defaultPayloadByteOrder) {
this.defaultPayloadByteOrder = defaultPayloadByteOrder;
}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
index 5245067c7e..47b5a86da6 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/ascii/protocol/ModbusAsciiProtocolLogic.java
@@ -27,6 +27,7 @@ import org.apache.plc4x.java.modbus.ascii.config.ModbusAsciiConfiguration;
import org.apache.plc4x.java.modbus.base.tag.ModbusTag;
import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
import org.apache.plc4x.java.spi.generation.ParseException;
@@ -120,7 +121,11 @@ public class ModbusAsciiProtocolLogic extends ModbusProtocolLogic<ModbusAsciiADU
responseCode = getErrorCode(errorResponse);
} else {
try {
- plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType());
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(tag.getByteOrder() != null) {
+ byteOrder = tag.getByteOrder();
+ }
+ plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType(), byteOrder);
responseCode = PlcResponseCode.OK;
} catch (ParseException e) {
// Add an error response code ...
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 0423c153f3..461b84014f 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
@@ -24,6 +24,7 @@ import org.apache.plc4x.java.api.value.*;
import org.apache.plc4x.java.api.types.PlcResponseCode;
import org.apache.plc4x.java.modbus.base.tag.*;
import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.Plc4xProtocolBase;
import org.apache.plc4x.java.spi.generation.*;
@@ -45,7 +46,7 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
protected Duration requestTimeout;
protected short unitIdentifier;
protected PlcTag pingAddress;
- protected ByteOrder defaultPayloadByteOrder;
+ protected ModbusByteOrder defaultPayloadByteOrder;
protected RequestTransactionManager tm;
protected final AtomicInteger transactionIdentifierGenerator = new AtomicInteger(1);
@@ -151,9 +152,13 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
protected ModbusPDU getWriteRequestPdu(PlcTag tag, PlcValue plcValue) {
if (tag instanceof ModbusTagCoil) {
ModbusTagCoil coil = (ModbusTagCoil) tag;
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(coil.getByteOrder() != null) {
+ byteOrder = coil.getByteOrder();
+ }
ModbusPDUWriteMultipleCoilsRequest request =
new ModbusPDUWriteMultipleCoilsRequest(coil.getAddress(), coil.getNumberOfElements(),
- fromPlcValue(tag, plcValue));
+ fromPlcValue(tag, plcValue, byteOrder));
if (request.getQuantity() == coil.getNumberOfElements()) {
return request;
} else {
@@ -162,9 +167,13 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
} else if (tag instanceof ModbusTagHoldingRegister) {
ModbusTagHoldingRegister holdingRegister = (ModbusTagHoldingRegister) tag;
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(holdingRegister.getByteOrder() != null) {
+ byteOrder = holdingRegister.getByteOrder();
+ }
ModbusPDUWriteMultipleHoldingRegistersRequest request =
new ModbusPDUWriteMultipleHoldingRegistersRequest(holdingRegister.getAddress(),
- holdingRegister.getLengthWords(), fromPlcValue(tag, plcValue));
+ holdingRegister.getLengthWords(), fromPlcValue(tag, plcValue, byteOrder));
if (request.getValue().length == holdingRegister.getLengthWords() * 2) {
return request;
} else {
@@ -173,6 +182,10 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
} else if (tag instanceof ModbusTagExtendedRegister) {
ModbusTagExtendedRegister extendedRegister = (ModbusTagExtendedRegister) tag;
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(extendedRegister.getByteOrder() != null) {
+ byteOrder = extendedRegister.getByteOrder();
+ }
int group1Address = extendedRegister.getAddress() % FC_EXTENDED_REGISTERS_FILE_RECORD_LENGTH;
int group2Address = 0;
int group1Quantity;
@@ -186,7 +199,7 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
//If request doesn't span file records, use a single group
group1Quantity = extendedRegister.getLengthWords();
ModbusPDUWriteFileRecordRequestItem group1 = new ModbusPDUWriteFileRecordRequestItem(
- (short) 6, group1FileNumber, group1Address, fromPlcValue(tag, plcValue));
+ (short) 6, group1FileNumber, group1Address, fromPlcValue(tag, plcValue, byteOrder));
itemArray = Collections.singletonList(group1);
} else {
//If it doesn't span a file record. e.g. 609998[10] request 2 words in first group and 8 in second.
@@ -194,9 +207,9 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
group2Quantity = extendedRegister.getLengthWords() - group1Quantity;
group2FileNumber = (short) (group1FileNumber + 1);
- plcValue1 = ArrayUtils.subarray(fromPlcValue(tag, plcValue), 0, group1Quantity);
+ plcValue1 = ArrayUtils.subarray(fromPlcValue(tag, plcValue, byteOrder), 0, group1Quantity);
plcValue2 = ArrayUtils.subarray(
- fromPlcValue(tag, plcValue), group1Quantity, fromPlcValue(tag, plcValue).length);
+ fromPlcValue(tag, plcValue, byteOrder), group1Quantity, fromPlcValue(tag, plcValue, byteOrder).length);
ModbusPDUWriteFileRecordRequestItem group1 = new ModbusPDUWriteFileRecordRequestItem(
(short) 6, group1FileNumber, group1Address, plcValue1);
ModbusPDUWriteFileRecordRequestItem group2 = new ModbusPDUWriteFileRecordRequestItem(
@@ -208,7 +221,7 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
throw new PlcRuntimeException("Unsupported write tag type " + tag.getClass().getName());
}
- protected PlcValue toPlcValue(ModbusPDU request, ModbusPDU response, ModbusDataType dataType) throws ParseException {
+ protected PlcValue toPlcValue(ModbusPDU request, ModbusPDU response, ModbusDataType dataType, ModbusByteOrder byteOrder) throws ParseException {
short tagDataTypeSize = dataType.getDataTypeSize();
if (request instanceof ModbusPDUReadDiscreteInputsRequest) {
@@ -234,11 +247,11 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
ModbusPDUReadInputRegistersRequest req = (ModbusPDUReadInputRegistersRequest) request;
ModbusPDUReadInputRegistersResponse resp = (ModbusPDUReadInputRegistersResponse) response;
- ReadBuffer io = new ReadBufferByteBased(resp.getValue(), defaultPayloadByteOrder);
+ ReadBuffer io = getReadBuffer(resp.getValue(), byteOrder);
if (tagDataTypeSize < 2) {
io.readByte();
}
- return DataItem.staticParse(io, dataType, Math.max(Math.round(req.getQuantity() / (tagDataTypeSize / 2.0f)), 1), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN);
+ return DataItem.staticParse(io, dataType, Math.max(Math.round(req.getQuantity() / (tagDataTypeSize / 2.0f)), 1), byteOrder == ModbusByteOrder.BIG_ENDIAN);
} else if (request instanceof ModbusPDUReadHoldingRegistersRequest) {
if (!(response instanceof ModbusPDUReadHoldingRegistersResponse)) {
throw new PlcRuntimeException("Unexpected response type. " +
@@ -246,11 +259,11 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
ModbusPDUReadHoldingRegistersRequest req = (ModbusPDUReadHoldingRegistersRequest) request;
ModbusPDUReadHoldingRegistersResponse resp = (ModbusPDUReadHoldingRegistersResponse) response;
- ReadBuffer io = new ReadBufferByteBased(resp.getValue(), defaultPayloadByteOrder);
+ ReadBuffer io = getReadBuffer(resp.getValue(), byteOrder);
if ((dataType != ModbusDataType.STRING) && tagDataTypeSize < 2) {
io.readByte();
}
- return DataItem.staticParse(io, dataType, Math.max(Math.round(req.getQuantity() / (tagDataTypeSize / 2.0f)), 1), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN);
+ return DataItem.staticParse(io, dataType, Math.max(Math.round(req.getQuantity() / (tagDataTypeSize / 2.0f)), 1), byteOrder == ModbusByteOrder.BIG_ENDIAN);
} else if (request instanceof ModbusPDUReadFileRecordRequest) {
if (!(response instanceof ModbusPDUReadFileRecordResponse)) {
throw new PlcRuntimeException("Unexpected response type. " +
@@ -263,11 +276,11 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
if (resp.getItems().size() == 2 && resp.getItems().size() == req.getItems().size()) {
//If request was split over file records, two groups in response should be received.
- io = new ReadBufferByteBased(ArrayUtils.addAll(resp.getItems().get(0).getData(), resp.getItems().get(1).getData()), defaultPayloadByteOrder);
+ io = getReadBuffer(ArrayUtils.addAll(resp.getItems().get(0).getData(), resp.getItems().get(1).getData()), byteOrder);
dataLength = (short) (resp.getItems().get(0).getLengthInBytes() + resp.getItems().get(1).getLengthInBytes() - (2 * FC_EXTENDED_REGISTERS_GROUP_HEADER_LENGTH));
} else if (resp.getItems().size() == 1 && resp.getItems().size() == req.getItems().size()) {
//If request was within a single file record, one group should be received.
- io = new ReadBufferByteBased(resp.getItems().get(0).getData(), defaultPayloadByteOrder);
+ io = getReadBuffer(resp.getItems().get(0).getData(), byteOrder);
dataLength = (short) (resp.getItems().get(0).getLengthInBytes() - FC_EXTENDED_REGISTERS_GROUP_HEADER_LENGTH);
} else {
throw new PlcRuntimeException("Unexpected number of groups in response. " +
@@ -276,12 +289,12 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
if (tagDataTypeSize < 2) {
io.readByte();
}
- return DataItem.staticParse(io, dataType, Math.round(Math.max(dataLength / 2.0f, 1) / Math.max(tagDataTypeSize / 2.0f, 1)), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN);
+ return DataItem.staticParse(io, dataType, Math.round(Math.max(dataLength / 2.0f, 1) / Math.max(tagDataTypeSize / 2.0f, 1)), byteOrder == ModbusByteOrder.BIG_ENDIAN);
}
return null;
}
- protected byte[] fromPlcValue(PlcTag tag, PlcValue plcValue) {
+ protected byte[] fromPlcValue(PlcTag tag, PlcValue plcValue, ModbusByteOrder byteOrder) {
ModbusDataType tagDataType = ((ModbusTag) tag).getDataType();
try {
if (tag instanceof ModbusTagCoil) {
@@ -293,7 +306,7 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
// If it's a List, convert the booleans in the list into an array of bytes.
else if(plcValue instanceof PlcList) {
PlcList valueList = (PlcList) plcValue;
- WriteBufferByteBased wb = new WriteBufferByteBased(((plcValue.getLength() - 1) / 8) + 1, defaultPayloadByteOrder);
+ WriteBufferByteBased wb = getWriteBuffer(((plcValue.getLength() - 1) / 8) + 1, byteOrder);
int paddingBits = 8 - (plcValue.getLength() % 8);
if(paddingBits < 8) {
for(int i = 0; i < paddingBits; i++) {
@@ -309,8 +322,13 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
PlcBOOL boolValue = (PlcBOOL) value;
wb.writeBit(boolValue.getBoolean());
}
- // Reverse the bytes to have the "unfinished bytes" at the end.
+
+ // Do the byte-swapping, if needed.
byte[] bytes = wb.getBytes();
+ if(byteOrder == ModbusByteOrder.BIG_ENDIAN_BYTE_SWAP || byteOrder == ModbusByteOrder.LITTLE_ENDIAN_BYTE_SWAP) {
+ bytes = byteSwap(bytes);
+ }
+ // Reverse the bytes to have the "unfinished bytes" at the end.
ArrayUtils.reverse(bytes);
return bytes;
}
@@ -319,9 +337,12 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
}
else if (plcValue instanceof PlcList) {
- WriteBufferByteBased writeBuffer = new WriteBufferByteBased(DataItem.getLengthInBytes(plcValue, tagDataType, plcValue.getLength(), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN), defaultPayloadByteOrder);
- DataItem.staticSerialize(writeBuffer, plcValue, tagDataType, plcValue.getLength(), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN);
+ WriteBufferByteBased writeBuffer = getWriteBuffer(DataItem.getLengthInBytes(plcValue, tagDataType, plcValue.getLength(), byteOrder == ModbusByteOrder.BIG_ENDIAN), byteOrder);
+ DataItem.staticSerialize(writeBuffer, plcValue, tagDataType, plcValue.getLength(), byteOrder == ModbusByteOrder.BIG_ENDIAN);
byte[] data = writeBuffer.getBytes();
+ if(byteOrder == ModbusByteOrder.BIG_ENDIAN_BYTE_SWAP || byteOrder == ModbusByteOrder.LITTLE_ENDIAN_BYTE_SWAP) {
+ data = byteSwap(data);
+ }
if (((ModbusTag) tag).getDataType() == ModbusDataType.BOOL) {
//Reverse Bits in each byte as
//they should be ordered like this: 8 7 6 5 4 3 2 1 | 0 0 0 0 0 0 0 9
@@ -333,9 +354,13 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
}
return data;
} else {
- WriteBufferByteBased writeBuffer = new WriteBufferByteBased(DataItem.getLengthInBytes(plcValue, tagDataType, plcValue.getLength(), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN), defaultPayloadByteOrder);
- DataItem.staticSerialize(writeBuffer, plcValue, tagDataType, plcValue.getLength(), defaultPayloadByteOrder == ByteOrder.BIG_ENDIAN);
- return writeBuffer.getBytes();
+ WriteBufferByteBased writeBuffer = getWriteBuffer(DataItem.getLengthInBytes(plcValue, tagDataType, plcValue.getLength(), byteOrder == ModbusByteOrder.BIG_ENDIAN), byteOrder);
+ DataItem.staticSerialize(writeBuffer, plcValue, tagDataType, plcValue.getLength(), byteOrder == ModbusByteOrder.BIG_ENDIAN);
+ byte[] bytes = writeBuffer.getBytes();
+ if(byteOrder == ModbusByteOrder.BIG_ENDIAN_BYTE_SWAP || byteOrder == ModbusByteOrder.LITTLE_ENDIAN_BYTE_SWAP) {
+ bytes = byteSwap(bytes);
+ }
+ return bytes;
}
} catch (SerializationException e) {
throw new PlcRuntimeException("Unable to parse PlcValue :- " + e);
@@ -383,4 +408,67 @@ public abstract class ModbusProtocolLogic<T extends ModbusADU> extends Plc4xProt
return new PlcList(Arrays.asList(values));
}
+ private ReadBuffer getReadBuffer(byte[] data, ModbusByteOrder byteOrder) {
+ switch (byteOrder) {
+ case LITTLE_ENDIAN: {
+ // [4, 3, 2, 1]
+ // [8, 7, 6, 5, 4, 3, 2, 1]
+ return new ReadBufferByteBased(data, ByteOrder.LITTLE_ENDIAN);
+ }
+ case BIG_ENDIAN_BYTE_SWAP: {
+ // [2, 1, 4, 3]
+ // [2, 1, 4, 3, 6, 5, 8, 7]
+ byte[] reordered = byteSwap(data);
+ return new ReadBufferByteBased(reordered, ByteOrder.BIG_ENDIAN);
+ }
+ case LITTLE_ENDIAN_BYTE_SWAP: {
+ // [3, 4, 1, 2]
+ // [7, 8, 5, 6, 3, 4, 1, 2]
+ byte[] reordered = byteSwap(data);
+ return new ReadBufferByteBased(reordered, ByteOrder.LITTLE_ENDIAN);
+ }
+ default:
+ // 16909060
+ // [1, 2, 3, 4]
+ // 72623859790382856
+ // [1, 2, 3, 4, 5, 6, 7, 8]
+ return new ReadBufferByteBased(data, ByteOrder.BIG_ENDIAN);
+ }
+ }
+
+ private WriteBufferByteBased getWriteBuffer(int size, ModbusByteOrder byteOrder) {
+ switch (byteOrder) {
+ case LITTLE_ENDIAN: {
+ // [4, 3, 2, 1]
+ // [8, 7, 6, 5, 4, 3, 2, 1]
+ return new WriteBufferByteBased(size, ByteOrder.LITTLE_ENDIAN);
+ }
+ case BIG_ENDIAN_BYTE_SWAP: {
+ // [2, 1, 4, 3]
+ // [2, 1, 4, 3, 6, 5, 8, 7]
+ return new WriteBufferByteBased(size, ByteOrder.BIG_ENDIAN);
+ }
+ case LITTLE_ENDIAN_BYTE_SWAP: {
+ // [3, 4, 1, 2]
+ // [7, 8, 5, 6, 3, 4, 1, 2]
+ return new WriteBufferByteBased(size, ByteOrder.LITTLE_ENDIAN);
+ }
+ default:
+ // 16909060
+ // [1, 2, 3, 4]
+ // 72623859790382856
+ // [1, 2, 3, 4, 5, 6, 7, 8]
+ return new WriteBufferByteBased(size, ByteOrder.BIG_ENDIAN);
+ }
+ }
+
+ public static byte[] byteSwap(byte[] in) {
+ byte[] out = new byte[in.length];
+ for(int i = 0; i < out.length; i += 2) {
+ out[i] = in[i + 1];
+ out[i + 1] = in[i];
+ }
+ return out;
+ }
+
}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/tag/ModbusTag.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/tag/ModbusTag.java
index 1b4cc0c29f..ba571f9ae1 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/tag/ModbusTag.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/base/tag/ModbusTag.java
@@ -23,6 +23,7 @@ import org.apache.plc4x.java.api.model.ArrayInfo;
import org.apache.plc4x.java.api.model.PlcTag;
import org.apache.plc4x.java.api.types.PlcValueType;
import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.codegen.WithOption;
import org.apache.plc4x.java.spi.generation.SerializationException;
import org.apache.plc4x.java.spi.generation.WriteBuffer;
@@ -46,6 +47,7 @@ public abstract class ModbusTag implements PlcTag, Serializable {
private final ModbusDataType dataType;
private final Short unitId;
+ private final ModbusByteOrder byteOrder;
public static ModbusTag of(String addressString) {
if (ModbusTagCoil.matches(addressString)) {
@@ -103,6 +105,11 @@ public abstract class ModbusTag implements PlcTag, Serializable {
this.unitId = Optional.ofNullable(config.get("unit-id"))
.map(Short::parseShort)
.orElse(null);
+ if(config.containsKey("byte-order")) {
+ this.byteOrder = ModbusByteOrder.valueOf(config.get("byte-order"));
+ } else {
+ this.byteOrder = null;
+ }
}
/**
@@ -117,6 +124,10 @@ public abstract class ModbusTag implements PlcTag, Serializable {
return unitId;
}
+ public ModbusByteOrder getByteOrder() {
+ return byteOrder;
+ }
+
/**
* Get the logical (configured) address
* @return The address which was configured and is different from what is used on the wire.
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/config/ModbusRtuConfiguration.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/config/ModbusRtuConfiguration.java
index 9525ef5f79..619e294244 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/config/ModbusRtuConfiguration.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/config/ModbusRtuConfiguration.java
@@ -18,13 +18,13 @@
*/
package org.apache.plc4x.java.modbus.rtu.config;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.configuration.PlcConnectionConfiguration;
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.Description;
import org.apache.plc4x.java.spi.configuration.annotations.Since;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.StringDefaultValue;
-import org.apache.plc4x.java.spi.generation.ByteOrder;
public class ModbusRtuConfiguration implements PlcConnectionConfiguration {
@@ -44,9 +44,11 @@ public class ModbusRtuConfiguration implements PlcConnectionConfiguration {
@Description("Default encoding used for transporting register values (Defaults to BIG_ENDIAN).\n" +
"Allowed values are: \n" +
" - BIG_ENDIAN\n" +
- " - LITTLE_ENDIAN")
+ " - LITTLE_ENDIAN\n" +
+ " - BIG_ENDIAN_BYTE_SWAP\n" +
+ " - LITTLE_ENDIAN_BYTE_SWAP\n")
@Since("0.13.0")
- private ByteOrder defaultPayloadByteOrder;
+ private ModbusByteOrder defaultPayloadByteOrder;
public int getRequestTimeout() {
return requestTimeout;
@@ -64,11 +66,11 @@ public class ModbusRtuConfiguration implements PlcConnectionConfiguration {
this.defaultUnitIdentifier = defaultUnitIdentifier;
}
- public ByteOrder getDefaultPayloadByteOrder() {
+ public ModbusByteOrder getDefaultPayloadByteOrder() {
return defaultPayloadByteOrder;
}
- public void setDefaultPayloadByteOrder(ByteOrder defaultPayloadByteOrder) {
+ public void setDefaultPayloadByteOrder(ModbusByteOrder defaultPayloadByteOrder) {
this.defaultPayloadByteOrder = defaultPayloadByteOrder;
}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
index c28b1287c2..e3ad6e07b1 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/rtu/protocol/ModbusRtuProtocolLogic.java
@@ -27,6 +27,7 @@ import org.apache.plc4x.java.modbus.base.tag.ModbusTag;
import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
import org.apache.plc4x.java.modbus.readwrite.*;
import org.apache.plc4x.java.modbus.rtu.config.ModbusRtuConfiguration;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
import org.apache.plc4x.java.spi.generation.ParseException;
@@ -120,7 +121,11 @@ public class ModbusRtuProtocolLogic extends ModbusProtocolLogic<ModbusRtuADU> im
responseCode = getErrorCode(errorResponse);
} else {
try {
- plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType());
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(tag.getByteOrder() != null) {
+ byteOrder = tag.getByteOrder();
+ }
+ plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType(), byteOrder);
responseCode = PlcResponseCode.OK;
} catch (ParseException e) {
// Add an error response code ...
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/config/ModbusTcpConfiguration.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/config/ModbusTcpConfiguration.java
index 4b8ec677a0..fe0214aadc 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/config/ModbusTcpConfiguration.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/config/ModbusTcpConfiguration.java
@@ -18,13 +18,13 @@
*/
package org.apache.plc4x.java.modbus.tcp.config;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.configuration.PlcConnectionConfiguration;
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.spi.configuration.annotations.Description;
import org.apache.plc4x.java.spi.configuration.annotations.Since;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue;
import org.apache.plc4x.java.spi.configuration.annotations.defaults.StringDefaultValue;
-import org.apache.plc4x.java.spi.generation.ByteOrder;
public class ModbusTcpConfiguration implements PlcConnectionConfiguration {
@@ -48,9 +48,11 @@ public class ModbusTcpConfiguration implements PlcConnectionConfiguration {
@Description("Default encoding used for transporting register values (Defaults to BIG_ENDIAN).\n" +
"Allowed values are: \n" +
" - BIG_ENDIAN\n" +
- " - LITTLE_ENDIAN")
+ " - LITTLE_ENDIAN\n" +
+ " - BIG_ENDIAN_BYTE_SWAP\n" +
+ " - LITTLE_ENDIAN_BYTE_SWAP\n")
@Since("0.13.0")
- private ByteOrder defaultPayloadByteOrder;
+ private ModbusByteOrder defaultPayloadByteOrder;
public int getRequestTimeout() {
return requestTimeout;
@@ -76,11 +78,11 @@ public class ModbusTcpConfiguration implements PlcConnectionConfiguration {
this.pingAddress = pingAddress;
}
- public ByteOrder getDefaultPayloadByteOrder() {
+ public ModbusByteOrder getDefaultPayloadByteOrder() {
return defaultPayloadByteOrder;
}
- public void setDefaultPayloadByteOrder(ByteOrder defaultPayloadByteOrder) {
+ public void setDefaultPayloadByteOrder(ModbusByteOrder defaultPayloadByteOrder) {
this.defaultPayloadByteOrder = defaultPayloadByteOrder;
}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
index 011127f6f7..ced1e1396d 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/tcp/protocol/ModbusTcpProtocolLogic.java
@@ -28,6 +28,7 @@ import org.apache.plc4x.java.modbus.base.protocol.ModbusProtocolLogic;
import org.apache.plc4x.java.modbus.base.tag.ModbusTagHandler;
import org.apache.plc4x.java.modbus.readwrite.*;
import org.apache.plc4x.java.modbus.tcp.config.ModbusTcpConfiguration;
+import org.apache.plc4x.java.modbus.types.ModbusByteOrder;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
import org.apache.plc4x.java.spi.generation.ParseException;
@@ -136,7 +137,11 @@ public class ModbusTcpProtocolLogic extends ModbusProtocolLogic<ModbusTcpADU> im
responseCode = getErrorCode(errorResponse);
} else {
try {
- plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType());
+ ModbusByteOrder byteOrder = defaultPayloadByteOrder;
+ if(tag.getByteOrder() != null) {
+ byteOrder = tag.getByteOrder();
+ }
+ plcValue = toPlcValue(requestPdu, responsePdu, tag.getDataType(), byteOrder);
responseCode = PlcResponseCode.OK;
} catch (ParseException e) {
// Add an error response code ...
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 5ed24e339e..98415071fc 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
@@ -19,13 +19,16 @@
package org.apache.plc4x.java.modbus.types;
public enum ModbusByteOrder {
- //A B C D
+ // [1, 2, 3, 4]
+ // [1, 2, 3, 4, 5, 6, 7, 8]
BIG_ENDIAN,
- //D C B A
+ // [4, 3, 2, 1]
+ // [8, 7, 6, 5, 4, 3, 2, 1]
LITTLE_ENDIAN,
- //B A D C
- BIG_ENDIAN_WORD_SWAP,
- //C D A B
- LITTLE_ENDIAN_WORD_SWAP
-
+ // [2, 1, 4, 3]
+ // [2, 1, 4, 3, 6, 5, 8, 7]
+ BIG_ENDIAN_BYTE_SWAP,
+ // [3, 4, 1, 2]
+ // [7, 8, 5, 6, 3, 4, 1, 2]
+ LITTLE_ENDIAN_BYTE_SWAP
}
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtils.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtils.java
deleted file mode 100644
index ba98349ad0..0000000000
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtils.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * 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.modbus.utils;
-
-public class ByteOrderUtils {
-
- /**
- * Byte order is 'A B C D'
- * @param num int number
- * @return int number in big endian format
- */
- public static int toBigEndian(int num){
- return num;
- }
-
- /**
- * Byte order is 'D C B A'
- * @param num int number
- * @return int number in little endian format
- */
- public static int toLittleEndian(int num){
- return Integer.reverseBytes(num);
- }
-
- /**
- * Byte order is 'B A D C'
- * @param num int number
- * @return int number in big endian swap format
- */
- public static int toBigEndianWordSwap(int num){
- return (num << 16)|(num >>> 16);
- }
-
- /**
- * Byte order is 'C D A B'
- * @param num int number
- * @return int number in little endian swap format
- */
- public static int toLittleEndianWordSwap(int num){
- return ((num&0xff00)>>>8)|
- ((num<<8)&0xff00)|
- ((num<<8)&0xff000000)|
- ((num &0xff000000)>>>8);
- }
-
- /**
- * Byte order is 'A B C D E F G H'
- * @param num long number
- * @return long number in big endian format
- */
- public static long toBigEndian(long num){
- return num;
- }
-
- /**
- * Byte order is 'H G F E D C B A'
- * @param num long number
- * @return long number in little endian format
- */
- public static long toLittleEndian(long num){
- return Long.reverseBytes(num);
- }
-
- /**
- * Byte order is 'B A D C F E H G'
- * @param num long number
- * @return long number in big endian format
- */
- public static long toBigEndianWordSwap(long num){
- return (num & 0x00ff00ff00ff00ffL) << 8 | (num >>> 8) & 0x00ff00ff00ff00ffL;
- }
-
- /**
- * Byte order is 'G H E F C D A B'
- * @param num long number
- * @return long number in little endian format
- */
- public static long toLittleEndianWordSwap(long num){
- return (num & 0xffff000000000000L) >>> 48 |
- (num & 0x0000ffff00000000L) >>> 16 |
- (num & 0x00000000ffff0000L) << 16 |
- (num & 0x000000000000ffffL) << 48;
- }
-
-}
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualDriverTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualDriverTest.java
new file mode 100644
index 0000000000..297adf5eb3
--- /dev/null
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualDriverTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.modbus;
+
+import org.apache.plc4x.java.DefaultPlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+
+public class ManualDriverTest {
+
+ /**
+ * Test programm made to work with the Modbus Simulator from https://www.modbustools.com/modbus_slave.html
+ * In contrast to others, this allows simulating the various types of modbus byte orders.
+ *
+ * @param args
+ * @throws Exception
+ */
+ public static void main(String[] args) throws Exception {
+ //final PlcConnection connection = new DefaultPlcDriverManager().getConnection("modbus-tcp://10.211.55.3?default-payload-byte-order=BIG_ENDIAN");
+ final PlcConnection connection = new DefaultPlcDriverManager().getConnection("modbus-tcp://10.211.55.3?default-payload-byte-order=LITTLE_ENDIAN");
+ //final PlcConnection connection = new DefaultPlcDriverManager().getConnection("modbus-tcp://10.211.55.3?default-payload-byte-order=BIG_ENDIAN_BYTE_SWAP");
+ //final PlcConnection connection = new DefaultPlcDriverManager().getConnection("modbus-tcp://10.211.55.3?default-payload-byte-order=LITTLE_ENDIAN_BYTE_SWAP");
+ final PlcReadRequest readRequest = connection.readRequestBuilder()
+ .addTagAddress("16 bit BigEndian", "holding-register:1:WORD{byte-order:'BIG_ENDIAN'}")
+ .addTagAddress("16 bit LittleEndian", "holding-register:2:WORD{byte-order:'LITTLE_ENDIAN'}")
+ .addTagAddress("32 bit BigEndian", "holding-register:3:DWORD{byte-order:'BIG_ENDIAN'}")
+ .addTagAddress("32 bit LittleEndian", "holding-register:5:DWORD{byte-order:'LITTLE_ENDIAN'}")
+ .addTagAddress("32 bit BigEndianByteSwap", "holding-register:7:DWORD{byte-order:'BIG_ENDIAN_BYTE_SWAP'}")
+ .addTagAddress("32 bit LittleEndianByteSwap", "holding-register:9:DWORD{byte-order:'LITTLE_ENDIAN_BYTE_SWAP'}")
+ .addTagAddress("64 bit BigEndian", "holding-register:11:LWORD{byte-order:'BIG_ENDIAN'}")
+ .addTagAddress("64 bit LittleEndian", "holding-register:15:LWORD{byte-order:'LITTLE_ENDIAN'}")
+ .addTagAddress("64 bit BigEndianByteSwap", "holding-register:19:LWORD{byte-order:'BIG_ENDIAN_BYTE_SWAP'}")
+ .addTagAddress("64 bit LittleEndianByteSwap", "holding-register:23:LWORD{byte-order:'LITTLE_ENDIAN_BYTE_SWAP'}")
+ .build();
+ final PlcReadResponse plcReadResponse = readRequest.execute().get();
+ connection.close();
+ System.out.println("16 bit BigEndian: " + String.format("0x%04X", plcReadResponse.getInteger("16 bit BigEndian")));
+ System.out.println("16 bit LittleEndian: " + String.format("0x%04X", plcReadResponse.getInteger("16 bit LittleEndian")));
+ System.out.println("32 bit BigEndian: " + String.format("0x%08X", plcReadResponse.getInteger("32 bit BigEndian")));
+ System.out.println("32 bit LittleEndian: " + String.format("0x%08X", plcReadResponse.getInteger("32 bit LittleEndian")));
+ System.out.println("32 bit BigEndianByteSwap: " + String.format("0x%08X", plcReadResponse.getInteger("32 bit BigEndianByteSwap")));
+ System.out.println("32 bit LittleEndianByteSwap: " + String.format("0x%08X", plcReadResponse.getInteger("32 bit LittleEndianByteSwap")));
+ System.out.println("64 bit BigEndian: " + String.format("0x%016X", plcReadResponse.getLong("64 bit BigEndian")));
+ System.out.println("64 bit LittleEndian: " + String.format("0x%016X", plcReadResponse.getLong("64 bit LittleEndian")));
+ System.out.println("64 bit BigEndianByteSwap: " + String.format("0x%016X", plcReadResponse.getLong("64 bit BigEndianByteSwap")));
+ System.out.println("64 bit LittleEndianByteSwap: " + String.format("0x%016X", plcReadResponse.getLong("64 bit LittleEndianByteSwap")));
+ }
+
+}
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusTCPDriverTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusTCPDriverTest.java
index 7f489b851f..39e3e0e656 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusTCPDriverTest.java
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusTCPDriverTest.java
@@ -72,7 +72,7 @@ public class ManualModbusTCPDriverTest extends ManualTest {
ManualModbusTCPDriverTest test = new ManualModbusTCPDriverTest("modbus-tcp://192.168.23.30");
test.addTestCase("holding-register:1:BOOL", new PlcBOOL(true)); // 0001
test.addTestCase("holding-register:2:BYTE", new PlcBYTE(42)); // 2A
- test.addTestCase("holding-register:3:WORD", new PlcWORD(42424)); // A5B8
+ //test.addTestCase("holding-register:3:WORD", new PlcWORD(42424)); // A5B8
test.addTestCase("holding-register:4:DWORD", new PlcDWORD(4242442424L)); // FCDE 88B8
// test.addTestCase("holding-register:6:LWORD", new PlcLWORD(4242442424242424242L)); // FCDE 88B8 FCDE 88B8
test.addTestCase("holding-register:10:SINT", new PlcSINT(-42)); // D6
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtilsTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtilsTest.java
deleted file mode 100644
index 6055fafb12..0000000000
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/utils/ByteOrderUtilsTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.plc4x.java.modbus.utils;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class ByteOrderUtilsTest {
-
- static final int INT_INPUT = 0x01020304;
- static final long LONG_INPUT = 0x0102030405060708L;
-
- @Test
- void testIntToBigEndian() {
- assertEquals(0x01020304, ByteOrderUtils.toBigEndian(INT_INPUT));
- assertEquals(INT_INPUT, ByteOrderUtils.toBigEndian(ByteOrderUtils.toBigEndian(INT_INPUT)));
- }
-
- @Test
- void testIntToLittleEndian() {
- assertEquals(0x04030201, ByteOrderUtils.toLittleEndian(INT_INPUT));
- assertEquals(INT_INPUT, ByteOrderUtils.toLittleEndian(ByteOrderUtils.toLittleEndian(INT_INPUT)));
- }
-
- @Test
- void testIntToBigEndianWordSwap() {
- assertEquals(0x03040102, ByteOrderUtils.toBigEndianWordSwap(INT_INPUT));
- assertEquals(INT_INPUT, ByteOrderUtils.toBigEndianWordSwap(ByteOrderUtils.toBigEndianWordSwap(INT_INPUT)));
- }
-
- @Test
- void testIntToLittleEndianWordSwap() {
- assertEquals(0x02010403, ByteOrderUtils.toLittleEndianWordSwap(INT_INPUT));
- assertEquals(INT_INPUT, ByteOrderUtils.toLittleEndianWordSwap(ByteOrderUtils.toLittleEndianWordSwap(INT_INPUT)));
- }
-
- @Test
- void testLongToBigEndian() {
- assertEquals(0x0102030405060708L, ByteOrderUtils.toBigEndian(LONG_INPUT));
- assertEquals(LONG_INPUT, ByteOrderUtils.toBigEndian(ByteOrderUtils.toBigEndian(LONG_INPUT)));
- }
-
- @Test
- void testLongToLittleEndian() {
- assertEquals(0x0807060504030201L, ByteOrderUtils.toLittleEndian(LONG_INPUT));
- assertEquals(LONG_INPUT, ByteOrderUtils.toLittleEndian(ByteOrderUtils.toLittleEndian(LONG_INPUT)));
- }
-
- @Test
- void testLongToBigEndianWordSwap() {
- assertEquals(0x0201040306050807L, ByteOrderUtils.toBigEndianWordSwap(LONG_INPUT));
- assertEquals(LONG_INPUT, ByteOrderUtils.toBigEndianWordSwap(ByteOrderUtils.toBigEndianWordSwap(LONG_INPUT)));
- }
-
- @Test
- void testLongToLittleEndianWordSwap() {
- assertEquals(0x0708050603040102L, ByteOrderUtils.toLittleEndianWordSwap(LONG_INPUT));
- assertEquals(LONG_INPUT, ByteOrderUtils.toLittleEndianWordSwap(ByteOrderUtils.toLittleEndianWordSwap(LONG_INPUT)));
- }
-
-}
\ No newline at end of file
diff --git a/src/site/asciidoc/users/protocols/modbus.adoc b/src/site/asciidoc/users/protocols/modbus.adoc
index 688b02a99f..5f210f50c6 100644
--- a/src/site/asciidoc/users/protocols/modbus.adoc
+++ b/src/site/asciidoc/users/protocols/modbus.adoc
@@ -68,11 +68,12 @@ Note the transport, port and option fields are optional.
In general all Modbus addresses have this format:
----
-{memory-Area}{start-address}:{data-type}[{array-size}]
+{memory-Area}{start-address}:{data-type}[{array-size}]:{name-value-tag-options}
----
If the array-size part is omitted, the size-default of `1` is assumed.
If the data-type part is omitted, it defaults to BOOL for Coils and Discrete Inputs and INT for input, holding and extended registers.
+If the name-value-tag-options part is omitted, simply no configuration fine-tuning is applied.
Additionally address can contain tag configuration:
----
@@ -80,6 +81,11 @@ Additionally address can contain tag configuration:
----
Specifying this value overrides value of `default-unit-id` parameter specified at the connection string.
+----
+{byte-order: 'LITTLE_ENDIAN'}
+----
+With this, can the default byte-order be overridden on a per-tag basis. If not provided the default-byte-order from the connection string is used, or BIG_ENDIAN, if this is also not provided.
+
==== Memory Areas
There are a number of memory areas defined in the Modbus specification.