diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index 65e2b593452..2c331debb5d 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -50,7 +50,7 @@ public enum BACnetVendorId { TACAB((int) 19, (int) 19, (String) "TAC AB"), HEWLETT_PACKARD_COMPANY((int) 20, (int) 20, (String) "Hewlett-Packard Company"), DORSETTES_INC((int) 21, (int) 21, (String) "Dorsette’s Inc."), - SIEMENS_SCHWEIZAG_FORMERLY_CERBERUSAG( + SIEMENS_SCHWEIZA_FORMERLY_CERBERUSAG( (int) 22, (int) 22, (String) "Siemens Schweiz AG (Formerly: Cerberus AG)"), YORK_CONTROLS_GROUP((int) 23, (int) 23, (String) "York Controls Group"), AUTOMATED_LOGIC_CORPORATION((int) 24, (int) 24, (String) "Automated Logic Corporation"), 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..b93405ea28b 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 @@ -19,6 +19,8 @@ package org.apache.plc4x.java.modbus.base.optimizer; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; import org.apache.plc4x.java.api.model.PlcTag; @@ -192,33 +194,7 @@ protected PlcReadResponse processReadResponses(PlcReadRequest readRequest, Map
(response.getResponseCode(), null));
- break;
- }
-
- // Coils are read completely different from registers.
- ModbusTagCoil coilTag = (ModbusTagCoil) modbusTag;
-
- // Calculate the byte that contains the response for this Coil
- byte[] responseData = response.getResponseData();
- int bitPosition = coilTag.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;
- }
- }
- // Read a normal register.
- else if (response.matchesRegister(modbusTag)) {
+ if (response.matchesRegister(modbusTag)) {
// If this response was invalid, return all associated addresses as equally invalid.
// TODO: Possibly it would be worth doing a single item request for each of these
// tags in order to find out which ones are actually invalid as if one item in the
@@ -230,7 +206,21 @@ else if (response.matchesRegister(modbusTag)) {
}
byte[] responseData = response.getResponseDataForTag(modbusTag);
- ReadBuffer readBuffer = getReadBuffer(responseData, modbusContext.getByteOrder());
+ ReadBuffer readBuffer = null;
+ if ((modbusTag instanceof ModbusTagCoil) || (modbusTag instanceof ModbusTagDiscreteInput)) {
+ //1. If this condition exists it is because we have an optimized buffer.
+ if ((modbusTag.getNumberOfElements() == 1) & (responseData.length > 2)) {
+ byte[] ret = new byte[2];
+ ret[1] = 0x00;
+ ret[0] = (isSet(responseData, modbusTag.getLogicalAddress()) ?(byte) 0x01 : 0x00);
+ readBuffer = getReadBuffer(ret, ModbusByteOrder.BIG_ENDIAN);
+ } else {
+ readBuffer = getReadBuffer(responseData, ModbusByteOrder.BIG_ENDIAN);
+ }
+ } else {
+ readBuffer = getReadBuffer(responseData, modbusContext.getByteOrder());
+ }
+
try {
PlcValue plcValue = DataItem.staticParse(readBuffer, modbusTag.getDataType(),
modbusTag.getNumberOfElements(),
@@ -407,11 +397,50 @@ public byte[] getResponseData() {
public byte[] getResponseDataForTag(ModbusTag modbusTag) {
byte[] itemData = new byte[modbusTag.getLengthBytes()];
- System.arraycopy(responseData, (modbusTag.getAddress() - startingAddress) * 2, itemData, 0, modbusTag.getLengthBytes());
+ int value = 0;
+ switch(modbusTag.getDataType()) {
+ case BOOL: {
+ itemData = new byte[responseData.length];
+ if ((modbusTag instanceof ModbusTagCoil) || (modbusTag instanceof ModbusTagDiscreteInput)) {
+ for (int i= 0; i < responseData.length; i++){
+ itemData[i] = byteReverse(responseData[i]);
+ }
+ } else {
+ for (int i= 0; i < responseData.length; i++){
+ itemData[i] = responseData[i];
+ }
+ }
+ }
+ break;
+ default:
+ System.arraycopy(responseData,
+ (modbusTag.getAddress() - startingAddress) * 2,
+ itemData, 0, modbusTag.getLengthBytes());
+ }
+
return itemData;
}
+
+ public static byte byteReverse(byte x) {
+ byte b = 0;
+ for (int i = 0; i < 8; ++i) {
+ b<<=1;
+ b|=( x &1);
+ x>>=1;
+ }
+ return b;
+ }
+
}
+
+ public boolean isSet(byte[] arr, int bit) {
+ int index = bit / 8;
+ int bitPosition = 8 - bit % 8;
+ return (arr[index] >> bitPosition & 1) == 1;
+ }
+
+
protected interface TagFactory {
PlcTag createTag(int address, int count, ModbusDataType dataType);
}
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
index 297adf5eb3b..2ab15cf87a7 100644
--- 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
@@ -35,7 +35,7 @@ public class ManualDriverTest {
*/
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.10.1.200:10502?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()
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 46f3b02d100..db1c5ee7db7 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
@@ -30,6 +30,29 @@ public class ManualModbusTCPDriverTest extends ManualTest {
*
* Located in "main"
*
+ * Reference server/client: ModbusTools
+ * https://github.com/serhmarch/ModbusTools/releases/tag/v0.3.8
+ *
+ * If you report any improvement points on the Modbus driver,
+ * please run the tests on the reference device indicated above.
+ * One of the virtues and weaknesses of the Modbus protocol is
+ * that it gives creative freedom to manufacturers for the implementation
+ * of Scalar types, so the indicated device is the reference.
+ *
+ * Modbus Application Protocol Specification, V1.1.b
+ * Section 4.2 Data Encoding
+ * MODBUS uses a ‘big-Endian’ representation for addresses and data items.
+ * This means that when a numerical quantity larger than a single byte is
+ * transmitted, the most significant byte is sent first. So for example
+ *
+ * Register size value
+ * 16 - bits 0x1234 the first byte sent is 0x12 then 0x34
+ *
+ *
+ * https://www.h-schmidt.net/FloatConverter/IEEE754.html
+ * 123456.00 -> 47 f1 20 00
+ * Modbus -> 20 00 47 f1
+
hurz_BOOL := TRUE;
hurz_BYTE := 42;
@@ -69,22 +92,22 @@ public ManualModbusTCPDriverTest(String connectionString) {
}
public static void main(String[] args) throws Exception {
- ManualModbusTCPDriverTest test = new ManualModbusTCPDriverTest("modbus-tcp://192.168.23.30");
+ ManualModbusTCPDriverTest test = new ManualModbusTCPDriverTest("modbus-tcp://10.10.1.200:10502?default-payload-byte-order=LITTLE_ENDIAN_BYTE_SWAP");
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:4:DWORD", new PlcDWORD(4242442424L)); // FCDE 88B8
+ test.addTestCase("holding-register:4:DWORD", new PlcDWORD(424244242L)); // 1949 7412
// test.addTestCase("holding-register:6:LWORD", new PlcLWORD(4242442424242424242L)); // FCDE 88B8 FCDE 88B8
test.addTestCase("holding-register:10:SINT", new PlcSINT(-42)); // D6
test.addTestCase("holding-register:11:USINT", new PlcUSINT(42)); // 2A
test.addTestCase("holding-register:12:INT", new PlcINT(-2424)); // F688
test.addTestCase("holding-register:13:UINT", new PlcUINT(42424)); // A5B8
- test.addTestCase("holding-register:14:DINT", new PlcDINT(-242442424)); // F18C 9F48
- test.addTestCase("holding-register:16:UDINT", new PlcUDINT(4242442424L));// FCDE 88B8
+ test.addTestCase("holding-register:14:DINT", new PlcDINT(-242442424)); // 1949 7412
+ test.addTestCase("holding-register:16:UDINT", new PlcUDINT(424244242L));// FCDE 88B8
test.addTestCase("holding-register:18:LINT", new PlcLINT(-4242442424242424242L));// C51F D117 B2FB B64E
test.addTestCase("holding-register:22:ULINT", new PlcULINT(4242442424242424242L));// 3AE0 2EE8 4D04 49B2
test.addTestCase("holding-register:26:REAL", new PlcREAL(3.141593F));// 4049 0FDC
- test.addTestCase("holding-register:28:LREAL", new PlcLREAL(2.71828182846D)); // 4005 BF0A 8B14 5FCF
+ test.addTestCase("holding-register:28:LREAL", new PlcLREAL(2.71)); // 4005 BF0A 8B14 5FCF
//test.addTestCase("holding-register:32:TIME", "PT1.234S"); // 04D2
//test.addTestCase("holding-register::LTIME", "PT24015H23M12.034002044S");
//test.addTestCase("holding-register::DATE", "1998-03-28");
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/base/optimizer/LittleEndianByteSwapTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/base/optimizer/LittleEndianByteSwapTest.java
index cad86516331..37f6c5fb166 100644
--- a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/base/optimizer/LittleEndianByteSwapTest.java
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/base/optimizer/LittleEndianByteSwapTest.java
@@ -98,6 +98,7 @@ public void testLittleEndianByteSwap() throws Exception {
input.put("variable44", new String[]{"holding-register:177:REAL", "0.3768"});
input.put("variable45", new String[]{"holding-register:181:REAL", "0.0"});
input.put("variable46", new String[]{"holding-register:185:REAL", "-0.01143"});
+
input.put("variable47", new String[]{"coil:1:BOOL", "false"});
input.put("variable48", new String[]{"coil:3:BOOL", "false"});
input.put("variable49", new String[]{"coil:5:BOOL", "true"});
@@ -183,9 +184,9 @@ public void testLittleEndianByteSwap() throws Exception {
input.put("variable129", new String[]{"coil:165:BOOL", "false"});
input.put("variable130", new String[]{"coil:167:BOOL", "false"});
input.put("variable131", new String[]{"coil:169:BOOL", "false"});
- input.put("variable132", new String[]{"coil:171:BOOL", "false"});
+ input.put("variable132", new String[]{"coil:171:BOOL", "true"});
input.put("variable133", new String[]{"coil:173:BOOL", "false"});
- input.put("variable134", new String[]{"coil:175:BOOL", "false"});
+ input.put("variable134", new String[]{"coil:175:BOOL", "true"});
PlcReader mockPlcReader = Mockito.mock(PlcReader.class);
PlcTagHandler modbusTagHandler = new ModbusTagHandler();
PlcReadRequest.Builder builder = new DefaultPlcReadRequest.Builder(mockPlcReader, modbusTagHandler);
@@ -248,7 +249,8 @@ public void testLittleEndianByteSwap() throws Exception {
Map