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/01/18 14:14:24 UTC

[plc4x] branch develop updated: - Started implementing the Modbus protocol.

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 3842331  - Started implementing the Modbus protocol.
3842331 is described below

commit 38423313e7c25e8b72cbe72c295c5b7b888135ad
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sat Jan 18 15:14:16 2020 +0100

    - Started implementing the Modbus protocol.
---
 protocols/modbus/pom.xml                           |  43 ++++
 .../plc4x/protocol/modbus/ModbusProtocol.java      |  46 ++++
 ...e.plc4x.plugins.codegenerator.protocol.Protocol |  19 ++
 .../main/resources/protocols/modbus/modbus.mspec   | 269 +++++++++++++++++++++
 protocols/pom.xml                                  |  19 +-
 5 files changed, 387 insertions(+), 9 deletions(-)

diff --git a/protocols/modbus/pom.xml b/protocols/modbus/pom.xml
new file mode 100644
index 0000000..d79335f
--- /dev/null
+++ b/protocols/modbus/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x</groupId>
+    <artifactId>plc4x-protocols</artifactId>
+    <version>0.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>plc4x-protocols-modbus</artifactId>
+
+  <name>Protocols: Modbus</name>
+  <description>Base protocol specifications for the Modbus protocol</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-build-utils-protocol-base-mspec</artifactId>
+      <version>0.7.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/protocols/modbus/src/main/java/org/apache/plc4x/protocol/modbus/ModbusProtocol.java b/protocols/modbus/src/main/java/org/apache/plc4x/protocol/modbus/ModbusProtocol.java
new file mode 100644
index 0000000..2251995
--- /dev/null
+++ b/protocols/modbus/src/main/java/org/apache/plc4x/protocol/modbus/ModbusProtocol.java
@@ -0,0 +1,46 @@
+/*
+ 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.protocol.modbus;
+
+import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class ModbusProtocol implements Protocol {
+
+    @Override
+    public String getName() {
+        return "modbus";
+    }
+
+    @Override
+    public Map<String, TypeDefinition> getTypeDefinitions() throws GenerationException {
+        InputStream schemaInputStream = ModbusProtocol.class.getResourceAsStream("/protocols/modbus/modbus.mspec");
+        if(schemaInputStream == null) {
+            throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
+        }
+        return new MessageFormatParser().parse(schemaInputStream);
+    }
+
+}
diff --git a/protocols/modbus/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol b/protocols/modbus/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000..b5211ef
--- /dev/null
+++ b/protocols/modbus/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.plc4x.protocol.modbus.ModbusProtocol
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
new file mode 100644
index 0000000..b23a810
--- /dev/null
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -0,0 +1,269 @@
+//
+// 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.
+//
+
+// Remark: The different fields are encoded in Big-endian.
+
+[type 'ModbusConstants'
+    [const          uint 16     'modbusTcpDefaultPort' '502']
+]
+
+[type 'ModbusTcpADU' [bit 'response']
+    // It is used for transaction pairing, the MODBUS server copies in the response the transaction
+    // identifier of the request.
+    [simple         uint 16     'transactionIdentifier']
+
+    // It is used for intra-system multiplexing. The MODBUS protocol is identified by the value 0.
+    [const          uint 16     'protocolIdentifier'    '0x0000']
+
+    // The length field is a byte count of the following fields, including the Unit Identifier and
+    // data fields.
+    [simple         uint 16     'length']
+
+    // This field is used for intra-system routing purpose. It is typically used to communicate to
+    // a MODBUS+ or a MODBUS serial line slave through a gateway between an Ethernet TCP-IP network
+    // and a MODBUS serial line. This field is set by the MODBUS Client in the request and must be
+    // returned with the same value in the response by the server.
+    [simple         uint 8      'unitItendifier']
+
+    // The actual modbus payload
+    [simple         ModbusPDU   'pdu' ['response']]
+]
+
+[type 'ModbusSerialADU' [bit 'response']
+    [simple         uint 16     'transactionId']
+    [reserved       uint 16     '0x0000']
+    [simple         uint 16     'length']
+    [simple         uint 8      'address']
+
+    // The actual modbus payload
+    [simple         ModbusPDU   'pdu' ['response']]
+]
+
+[discriminatedType 'ModbusPDU' [bit 'response']
+    [discriminator  uint 7      'function']
+    [simple         bit         'error']
+    [typeSwitch 'error','function','response'
+        ['true'                     ModbusPduError
+            [simple     uint 8      'exceptionCode']
+        ]
+
+        // Bit Access
+        ['false','0x02','false'     ModbusPduReadDiscreteInputsRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+        ['false','0x02','true'      ModbusPduReadDiscreteInputsResponse
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x01','false'     ModbusPduReadCoilsRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+        ['false','0x01','true'      ModbusPduReadCoilsResponse
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x05','false'     ModbusPduWriteSingleCoilRequest
+            [simple     uint 16     'address']
+            [simple     uint 16     'value']
+        ]
+        ['false','0x05','true'      ModbusPduWriteSingleCoilResponse
+            [simple     uint 16     'address']
+            [simple     uint 16     'value']
+        ]
+
+        ['false','0x0F','false'     ModbusPduWriteMultipleCoilsRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+        ['false','0x0F','true'      ModbusPduWriteMultipleCoilsResponse
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+
+        // Uint 16 Access (short)
+        ['false','0x04','false'     ModbusPduReadInputRegistersRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+        ['false','0x04','true'      ModbusPduReadInputRegistersResponse
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x03','false'     ModbusPduReadHoldingRegistersRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+        ['false','0x03','true'      ModbusPduReadHoldingRegistersResponse
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x06','false'     ModbusPduWriteSingleRegisterRequest
+            [simple     uint 16     'address']
+            [simple     uint 16     'value']
+        ]
+        ['false','0x06','true'      ModbusPduWriteSingleRegisterResponse
+            [simple     uint 16     'address']
+            [simple     uint 16     'value']
+        ]
+
+        ['false','0x10','false'     ModbusPduWriteMultipleRegistersRequest
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+        ['false','0x10','true'      ModbusPduWriteMultipleRegistersResponse
+            [simple     uint 16     'startingAddress']
+            [simple     uint 16     'quantity']
+        ]
+
+        ['false','0x17','false'     ModbusPduReadWriteMultipleRegistersRequest
+            [simple     uint 16     'readStartingAddress']
+            [simple     uint 16     'readQuantity']
+            [simple     uint 16     'writeStartingAddress']
+            [simple     uint 16     'writeQuantity']
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+        ['false','0x17','true'      ModbusPduReadWriteMultipleRegistersResponse
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x16','false'     ModbusPduMaskWriteRegisterRequest
+            [simple     uint 16     'referenceAddress']
+            [simple     uint 16     'andMask']
+            [simple     uint 16     'orMask']
+        ]
+        ['false','0x16','true'      ModbusPduMaskWriteRegisterResponse
+            [simple     uint 16     'referenceAddress']
+            [simple     uint 16     'andMask']
+            [simple     uint 16     'orMask']
+        ]
+
+        ['false','0x18','false'     ModbusPduReadFifoQueueRequest
+            [simple     uint 16     'fifoPointerAddress']
+        ]
+        ['false','0x18','true'      ModbusPduReadFifoQueueResponse
+            [implicit   uint 16     'byteCount'     'fifoValue.lengthInBytes + 2']
+            [implicit   uint 16     'fifoCount'     'fifoValue.lengthInBytes / 2']
+            [array      uint 16     'fifoValue'     count   'fifoCount']
+        ]
+
+        // File Record Access
+        ['false','0x14','false'     ModbusPduReadFileRecordRequest
+            [implicit   uint 8      'byteCount'                 'items.lengthInBytes']
+            [array      ModbusPduReadFileRecordRequestItem      'items' length 'byteCount']
+        ]
+        ['false','0x14','true'      ModbusPduReadFileRecordResponse
+            [implicit   uint 8      'byteCount'                 'items.lengthInBytes']
+            [array      ModbusPduReadFileRecordResponseItem     'items' length 'byteCount']
+        ]
+
+        ['false','0x15','false'     ModbusPduWriteFileRecordRequest
+            [implicit   uint 8      'byteCount'                 'items.lengthInBytes']
+            [array      ModbusPduWriteFileRecordRequestItem     'items' length 'byteCount']
+        ]
+        ['false','0x15','true'      ModbusPduWriteFileRecordResponse
+            [implicit   uint 8      'byteCount'                 'items.lengthInBytes']
+            [array      ModbusPduWriteFileRecordResponseItem    'items' length 'byteCount']
+        ]
+
+        // Diagnostics (Serial Line Only)
+        ['false','0x07','false'     ModbusPduReadExceptionStatusRequest
+        ]
+        ['false','0x07','true'      ModbusPduReadExceptionStatusResponse
+            [simple     uint 8      'value']
+        ]
+
+        ['false','0x08','false'     ModbusPduDiagnosticRequest
+            // TODO: Implement the sub-request discriminated type [simple uint 8  'subfunction']
+        ]
+        ['false','0x08','true'      ModbusPduDiagnosticResponse
+            // TODO: Implement the sub-request discriminated type [simple uint 8  'subfunction']
+        ]
+
+        ['false','0x0B','false'     ModbusPduGetComEventCounterRequest
+        ]
+        ['false','0x0B','true'      ModbusPduGetComEventCounterResponse
+            [simple     uint 16     'status']
+            [simple     uint 16     'eventCount']
+        ]
+
+        ['false','0x0C','false'     ModbusPduGetComEventLogRequest
+        ]
+        ['false','0x0C','true'      ModbusPduGetComEventLogResponse
+            [implicit   uint 8      'byteCount'    'events.lengthInBytes + 6']
+            [simple     uint 16     'status']
+            [simple     uint 16     'eventCount']
+            [simple     uint 16     'messageCount']
+            [array      int 8       'events'       count   'byteCount - 6']
+        ]
+
+        ['false','0x11','false'     ModbusPduReportServerIdRequest
+        ]
+        ['false','0x11','true'      ModbusPduReportServerIdResponse
+            // TODO: This is not specified very well in the spec ... investigate.
+            [implicit   uint 8      'byteCount'     'value.lengthInBytes']
+            [array      int 8       'value'         count   'byteCount']
+        ]
+
+        ['false','0x2B','false'     ModbusPduReadDeviceIdentificationRequest
+        ]
+        ['false','0x2B','true'      ModbusPduReadDeviceIdentificationResponse
+        ]
+    ]
+]
+
+[type 'ModbusPduReadFileRecordRequestItem'
+    [simple     uint 8     'referenceType']
+    [simple     uint 16    'fileNumber']
+    [simple     uint 16    'recordNumber']
+    [simple     uint 16    'recordLength']
+]
+
+[type 'ModbusPduReadFileRecordResponseItem'
+    [implicit   uint 8     'dataLength'     'data.lengthInBytes + 1']
+    [simple     uint 8     'referenceType']
+    [array      uint 16    'data'           length  'dataLength - 1']
+]
+
+[type 'ModbusPduWriteFileRecordRequestItem'
+    [simple     uint 8     'referenceType']
+    [simple     uint 16    'fileNumber']
+    [simple     uint 16    'recordNumber']
+    [implicit   uint 16    'recordLength'   'recordData.lengthInBytes / 2']
+    [array      uint 16    'recordData'     length  'recordLength * 2']
+]
+
+[type 'ModbusPduWriteFileRecordResponseItem'
+    [simple     uint 8     'referenceType']
+    [simple     uint 16    'fileNumber']
+    [simple     uint 16    'recordNumber']
+    [implicit   uint 16    'recordLength'   'recordData.lengthInBytes / 2']
+    [array      uint 16    'recordData'     length  'recordLength * 2']
+]
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 8d3804c..c77fa40 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -33,6 +33,16 @@
   <name>Protocols</name>
   <description>Base protocol specifications.</description>
 
+  <modules>
+    <module>ab-eth</module>
+    <module>amsads</module>
+    <module>bacnetip</module>
+    <module>df1</module>
+    <module>knxnetip</module>
+    <module>modbus</module>
+    <module>s7</module>
+  </modules>
+
   <build>
     <plugins>
       <!--
@@ -189,15 +199,6 @@
     </plugins>
   </build>
 
-  <modules>
-    <module>amsads</module>
-    <module>ab-eth</module>
-    <module>bacnetip</module>
-    <module>df1</module>
-    <module>knxnetip</module>
-    <module>s7</module>
-  </modules>
-
   <profiles>
     <profile>
       <id>with-proxies</id>