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 2020/11/18 21:56:49 UTC

[plc4x] branch feature/plc4go updated: - Started working on the support of reading data which is smaller than 16 bits in modbus - Added support for reading Modbus BitStrings from registers - Added tests for Modbus

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

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


The following commit(s) were added to refs/heads/feature/plc4go by this push:
     new ad9524a  - Started working on the support of reading data which is smaller than 16 bits in modbus - Added support for reading Modbus BitStrings from registers - Added tests for Modbus
ad9524a is described below

commit ad9524afacb72166128010b4c215d61721398abf
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Nov 18 22:56:41 2020 +0100

    - Started working on the support of reading data which is smaller than 16 bits in modbus
    - Added support for reading Modbus BitStrings from registers
    - Added tests for Modbus
---
 .../plc4go/modbus/readwrite/model/DataItem.go      |  24 ++---
 .../java/modbus/protocol/ModbusProtocolLogic.java  |  10 +-
 .../plc4x/java/modbus/ManualModbusDriverTest.java  | 103 +++++++++++++++++++++
 .../main/resources/protocols/modbus/modbus.mspec   |   8 +-
 .../protocols/modbus/manual-test-capture.pcapng    | Bin 0 -> 224232 bytes
 .../protocols/s7/manual-test-capture.pcapng        | Bin 0 -> 65868 bytes
 .../plc4c/generated-sources/modbus/src/data_item.c |   8 +-
 7 files changed, 128 insertions(+), 25 deletions(-)

diff --git a/plc4go/internal/plc4go/modbus/readwrite/model/DataItem.go b/plc4go/internal/plc4go/modbus/readwrite/model/DataItem.go
index c9233cf..fb74f46 100644
--- a/plc4go/internal/plc4go/modbus/readwrite/model/DataItem.go
+++ b/plc4go/internal/plc4go/modbus/readwrite/model/DataItem.go
@@ -52,14 +52,14 @@ func DataItemParse(io *utils.ReadBuffer, dataType string, numberOfValues uint16)
                 value = append(value, values.NewPlcBOOL(_item))
             }
             return values.NewPlcList(value), nil
-        case dataType == "IEC61131_BYTE" && numberOfValues == 1: // BYTE
+        case dataType == "IEC61131_BYTE" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             value, _valueErr := io.ReadUint8(8)
             if _valueErr != nil {
                 return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
             }
-            return values.NewPlcBYTE(value), nil
+            return values.NewPlcBitString(value), nil
         case dataType == "IEC61131_BYTE": // List
 
             // Array Field (value)
@@ -72,14 +72,14 @@ func DataItemParse(io *utils.ReadBuffer, dataType string, numberOfValues uint16)
                 value = append(value, values.NewPlcUSINT(_item))
             }
             return values.NewPlcList(value), nil
-        case dataType == "IEC61131_WORD" && numberOfValues == 1: // WORD
+        case dataType == "IEC61131_WORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             value, _valueErr := io.ReadUint16(16)
             if _valueErr != nil {
                 return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
             }
-            return values.NewPlcWORD(value), nil
+            return values.NewPlcBitString(value), nil
         case dataType == "IEC61131_WORD": // List
 
             // Array Field (value)
@@ -92,14 +92,14 @@ func DataItemParse(io *utils.ReadBuffer, dataType string, numberOfValues uint16)
                 value = append(value, values.NewPlcUINT(_item))
             }
             return values.NewPlcList(value), nil
-        case dataType == "IEC61131_DWORD" && numberOfValues == 1: // DWORD
+        case dataType == "IEC61131_DWORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             value, _valueErr := io.ReadUint32(32)
             if _valueErr != nil {
                 return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
             }
-            return values.NewPlcDWORD(value), nil
+            return values.NewPlcBitString(value), nil
         case dataType == "IEC61131_DWORD": // List
 
             // Array Field (value)
@@ -112,14 +112,14 @@ func DataItemParse(io *utils.ReadBuffer, dataType string, numberOfValues uint16)
                 value = append(value, values.NewPlcUDINT(_item))
             }
             return values.NewPlcList(value), nil
-        case dataType == "IEC61131_LWORD" && numberOfValues == 1: // LWORD
+        case dataType == "IEC61131_LWORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             value, _valueErr := io.ReadUint64(64)
             if _valueErr != nil {
                 return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
             }
-            return values.NewPlcLWORD(value), nil
+            return values.NewPlcBitString(value), nil
         case dataType == "IEC61131_LWORD": // List
 
             // Array Field (value)
@@ -398,7 +398,7 @@ func DataItemSerialize(io *utils.WriteBuffer, value api.PlcValue, dataType strin
                     return errors.New("Error serializing 'value' field " + _itemErr.Error())
                 }
             }
-        case dataType == "IEC61131_BYTE" && numberOfValues == 1: // BYTE
+        case dataType == "IEC61131_BYTE" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             if _err := io.WriteUint8(8, value.GetUint8()); _err != nil {
@@ -413,7 +413,7 @@ func DataItemSerialize(io *utils.WriteBuffer, value api.PlcValue, dataType strin
                     return errors.New("Error serializing 'value' field " + _itemErr.Error())
                 }
             }
-        case dataType == "IEC61131_WORD" && numberOfValues == 1: // WORD
+        case dataType == "IEC61131_WORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             if _err := io.WriteUint16(16, value.GetUint16()); _err != nil {
@@ -428,7 +428,7 @@ func DataItemSerialize(io *utils.WriteBuffer, value api.PlcValue, dataType strin
                     return errors.New("Error serializing 'value' field " + _itemErr.Error())
                 }
             }
-        case dataType == "IEC61131_DWORD" && numberOfValues == 1: // DWORD
+        case dataType == "IEC61131_DWORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             if _err := io.WriteUint32(32, value.GetUint32()); _err != nil {
@@ -443,7 +443,7 @@ func DataItemSerialize(io *utils.WriteBuffer, value api.PlcValue, dataType strin
                     return errors.New("Error serializing 'value' field " + _itemErr.Error())
                 }
             }
-        case dataType == "IEC61131_LWORD" && numberOfValues == 1: // LWORD
+        case dataType == "IEC61131_LWORD" && numberOfValues == 1: // BitString
 
             // Simple Field (value)
             if _err := io.WriteUint64(64, value.GetUint64()); _err != nil {
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
index 146ec1e..66b42b4 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
@@ -256,10 +256,10 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> impleme
             return new ModbusPDUReadCoilsRequest(coil.getAddress(), coil.getNumberOfElements());
         } else if(field instanceof ModbusFieldInputRegister) {
             ModbusFieldInputRegister inputRegister = (ModbusFieldInputRegister) field;
-            return new ModbusPDUReadInputRegistersRequest(inputRegister.getAddress(), inputRegister.getLengthWords());
+            return new ModbusPDUReadInputRegistersRequest(inputRegister.getAddress(), Math.max(inputRegister.getLengthWords(), 1));
         } else if(field instanceof ModbusFieldHoldingRegister) {
             ModbusFieldHoldingRegister holdingRegister = (ModbusFieldHoldingRegister) field;
-            return new ModbusPDUReadHoldingRegistersRequest(holdingRegister.getAddress(), holdingRegister.getLengthWords());
+            return new ModbusPDUReadHoldingRegistersRequest(holdingRegister.getAddress(), Math.max(holdingRegister.getLengthWords(), 1));
         } else if(field instanceof ModbusExtendedRegister) {
             ModbusExtendedRegister extendedRegister = (ModbusExtendedRegister) field;
             int group1Address = extendedRegister.getAddress() % 10000;
@@ -379,7 +379,7 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> impleme
             ModbusPDUReadInputRegistersRequest req = (ModbusPDUReadInputRegistersRequest) request;
             ModbusPDUReadInputRegistersResponse resp = (ModbusPDUReadInputRegistersResponse) response;
             ReadBuffer io = new ReadBuffer(resp.getValue());
-            return DataItemIO.staticParse(io, dataType, Math.round(req.getQuantity()/(fieldDataTypeSize/2.0f)));
+            return DataItemIO.staticParse(io, dataType, Math.round(req.getQuantity()/Math.max(fieldDataTypeSize/2.0f, 1)));
         } else if (request instanceof ModbusPDUReadHoldingRegistersRequest) {
             if (!(response instanceof ModbusPDUReadHoldingRegistersResponse)) {
                 throw new PlcRuntimeException("Unexpected response type. " +
@@ -388,7 +388,7 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> impleme
             ModbusPDUReadHoldingRegistersRequest req = (ModbusPDUReadHoldingRegistersRequest) request;
             ModbusPDUReadHoldingRegistersResponse resp = (ModbusPDUReadHoldingRegistersResponse) response;
             ReadBuffer io = new ReadBuffer(resp.getValue());
-            return DataItemIO.staticParse(io, dataType, Math.round(req.getQuantity()/(fieldDataTypeSize/2.0f)));
+            return DataItemIO.staticParse(io, dataType, Math.round(req.getQuantity()/Math.max(fieldDataTypeSize/2.0f, 1)));
         } else if (request instanceof ModbusPDUReadFileRecordRequest) {
             if (!(response instanceof ModbusPDUReadFileRecordResponse)) {
                 throw new PlcRuntimeException("Unexpected response type. " +
@@ -412,7 +412,7 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> impleme
                   "Expected " + req.getItems().length + ", but got " + resp.getItems().length);
             }
 
-            return DataItemIO.staticParse(io, dataType, Math.round((dataLength/2.0f)/(fieldDataTypeSize/2.0f)));
+            return DataItemIO.staticParse(io, dataType, Math.round(Math.max(dataLength/2.0f, 1)/Math.max(fieldDataTypeSize/2.0f, 1)));
         }
         return null;
     }
diff --git a/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusDriverTest.java b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusDriverTest.java
new file mode 100644
index 0000000..764a711
--- /dev/null
+++ b/plc4j/drivers/modbus/src/test/java/org/apache/plc4x/java/modbus/ManualModbusDriverTest.java
@@ -0,0 +1,103 @@
+/*
+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.test.manual.ManualTest;
+
+import java.util.Arrays;
+
+public class ManualModbusDriverTest extends ManualTest {
+
+    /*
+     * Test program code on the PLC with the test-data.
+     *
+     * Located in "main"
+     *
+
+    hurz_BOOL  := TRUE;
+	hurz_BYTE  := 42;
+	hurz_WORD  := 42424;
+	hurz_DWORD := 4242442424;
+	hurz_LWORD := 4242442424242424242;
+	hurz_SINT  := -42;
+	hurz_USINT := 42;
+	hurz_INT   := -2424;
+	hurz_UINT  := 42424;
+	hurz_DINT  := -242442424;
+	hurz_UDINT := 4242442424;
+	hurz_LINT  := -4242442424242424242;
+	hurz_ULINT := 4242442424242424242;
+	hurz_REAL  := 3.14159265359;
+	hurz_LREAL := 2.71828182846;
+	hurz_TIME  := T#1S234MS;
+	hurz_LTIME := LTIME#1000D15H23M12S34MS2US44NS;
+	hurz_DATE  := D#1998-03-28;
+	//hurz_LDATE:LDATE;
+	hurz_TIME_OF_DAY 	:= TIME_OF_DAY#15:36:30.123;
+	hurz_TOD         	:= TOD#16:17:18.123;
+	//hurz_LTIME_OF_DAY:LTIME_OF_DAY;
+	//hurz_LTOD:LTOD;
+	hurz_DATE_AND_TIME 	:= DATE_AND_TIME#1996-05-06-15:36:30;
+	hurz_DT				:= DT#1972-03-29-00:00:00;
+	//hurz_LDATE_AND_TIME:LDATE_AND_TIME;
+	//hurz_LDT:LDT;
+	hurz_STRING			:= 'hurz';
+	hurz_WSTRING		:= "wolf";
+
+     *
+     */
+
+    public ManualModbusDriverTest(String connectionString) {
+        super(connectionString);
+    }
+
+    public static void main(String[] args) throws Exception {
+        ManualModbusDriverTest test = new ManualModbusDriverTest("modbus:tcp://192.168.23.30");
+        //test.addTestCase("holding-register:1:BOOL", true); // 0001
+        //test.addTestCase("holding-register:2:BYTE", Arrays.asList(false, false, true, false, true, false, true, false)); // 002A
+        test.addTestCase("holding-register:3:WORD", Arrays.asList(true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false)); // A5B8
+        test.addTestCase("holding-register:4:DWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false)); // FCDE 88B8
+        test.addTestCase("holding-register:6:LWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false, true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false)); // FCDE 88B [...]
+        //test.addTestCase("holding-register:10:SINT", -42); // FFD6
+        //test.addTestCase("holding-register:11:USINT", 42); // 002A
+        test.addTestCase("holding-register:12:INT", -2424); // F688
+        test.addTestCase("holding-register:13:UINT", 42424); // A5B8
+        test.addTestCase("holding-register:14:DINT", -242442424); // F18C 9F48
+        test.addTestCase("holding-register:16:UDINT", 4242442424L);// FCDE 88B8
+        test.addTestCase("holding-register:18:LINT", -4242442424242424242L);// C51F D117 B2FB B64E
+        test.addTestCase("holding-register:22:ULINT", 4242442424242424242L);// 3AE0 2EE8 4D04 49B2
+        test.addTestCase("holding-register:26:REAL", 3.141593F);// 4049 0FDC
+        test.addTestCase("holding-register:28:LREAL", 2.71828182846D); // 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");
+        //test.addTestCase("holding-register::TIME_OF_DAY", "15:36:30.123");
+        //test.addTestCase("holding-register::TOD", "16:17:18.123");
+        //test.addTestCase("holding-register::DATE_AND_TIME", "1996-05-06T15:36:30");
+        //test.addTestCase("holding-register::DT", "1992-03-29T00:00");
+        //test.addTestCase("holding-register::LDATE_AND_TIME", "1978-03-28T15:36:30");
+        //test.addTestCase("holding-register::LDT", "1978-03-28T15:36:30");
+        //test.addTestCase("holding-register::CHAR", "H");
+        //test.addTestCase("holding-register::WCHAR", "w");
+        //test.addTestCase("holding-register::STRING(10)", "hurz");
+        //test.addTestCase("holding-register::WSTRING(10)", "wolf");
+        test.run();
+    }
+
+}
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index 80e1c44..2c246f9 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -279,25 +279,25 @@
         ['IEC61131_BOOL' List
             [array bit 'value' count 'numberOfValues']
         ]
-        ['IEC61131_BYTE','1' BYTE
+        ['IEC61131_BYTE','1' BitString
             [simple uint 8 'value']
         ]
         ['IEC61131_BYTE' List
             [array uint 8 'value' count 'numberOfValues']
         ]
-        ['IEC61131_WORD','1' WORD
+        ['IEC61131_WORD','1' BitString
             [simple uint 16 'value']
         ]
         ['IEC61131_WORD' List
             [array uint 16 'value' count 'numberOfValues']
         ]
-        ['IEC61131_DWORD','1' DWORD
+        ['IEC61131_DWORD','1' BitString
             [simple uint 32 'value']
         ]
         ['IEC61131_DWORD' List
             [array uint 32 'value' count 'numberOfValues']
         ]
-        ['IEC61131_LWORD','1' LWORD
+        ['IEC61131_LWORD','1' BitString
             [simple uint 64 'value']
         ]
         ['IEC61131_LWORD' List
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/manual-test-capture.pcapng b/protocols/modbus/src/test/resources/protocols/modbus/manual-test-capture.pcapng
new file mode 100644
index 0000000..90228f3
Binary files /dev/null and b/protocols/modbus/src/test/resources/protocols/modbus/manual-test-capture.pcapng differ
diff --git a/protocols/s7/src/test/resources/protocols/s7/manual-test-capture.pcapng b/protocols/s7/src/test/resources/protocols/s7/manual-test-capture.pcapng
new file mode 100644
index 0000000..77f72da
Binary files /dev/null and b/protocols/s7/src/test/resources/protocols/s7/manual-test-capture.pcapng differ
diff --git a/sandbox/plc4c/generated-sources/modbus/src/data_item.c b/sandbox/plc4c/generated-sources/modbus/src/data_item.c
index b2488ca..f981f79 100644
--- a/sandbox/plc4c/generated-sources/modbus/src/data_item.c
+++ b/sandbox/plc4c/generated-sources/modbus/src/data_item.c
@@ -59,7 +59,7 @@ plc4c_return_code plc4c_modbus_read_write_data_item_parse(plc4c_spi_read_buffer*
 
                     // Array field (value)
         } else 
-        if((strcmp(dataType, "IEC61131_BYTE") == 0) && (numberOfValues == 1)) { /* BYTE */
+        if((strcmp(dataType, "IEC61131_BYTE") == 0) && (numberOfValues == 1)) { /* BitString */
 
                 // Simple Field (value)
                 uint8_t value = 0;
@@ -75,7 +75,7 @@ plc4c_return_code plc4c_modbus_read_write_data_item_parse(plc4c_spi_read_buffer*
 
                     // Array field (value)
         } else 
-        if((strcmp(dataType, "IEC61131_WORD") == 0) && (numberOfValues == 1)) { /* WORD */
+        if((strcmp(dataType, "IEC61131_WORD") == 0) && (numberOfValues == 1)) { /* BitString */
 
                 // Simple Field (value)
                 uint16_t value = 0;
@@ -91,7 +91,7 @@ plc4c_return_code plc4c_modbus_read_write_data_item_parse(plc4c_spi_read_buffer*
 
                     // Array field (value)
         } else 
-        if((strcmp(dataType, "IEC61131_DWORD") == 0) && (numberOfValues == 1)) { /* DWORD */
+        if((strcmp(dataType, "IEC61131_DWORD") == 0) && (numberOfValues == 1)) { /* BitString */
 
                 // Simple Field (value)
                 uint32_t value = 0;
@@ -107,7 +107,7 @@ plc4c_return_code plc4c_modbus_read_write_data_item_parse(plc4c_spi_read_buffer*
 
                     // Array field (value)
         } else 
-        if((strcmp(dataType, "IEC61131_LWORD") == 0) && (numberOfValues == 1)) { /* LWORD */
+        if((strcmp(dataType, "IEC61131_LWORD") == 0) && (numberOfValues == 1)) { /* BitString */
 
                 // Simple Field (value)
                 uint64_t value = 0;