This is an automated email from the ASF dual-hosted git repository.
chrisdutz 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 7ac57b3ced feat: Add SLMP (MELSEC Communication 3E) protocol module
(read-only wire layer) (#2597)
7ac57b3ced is described below
commit 7ac57b3cede971093167d72958868fd189b99efc
Author: LivingLikeKrillin <[email protected]>
AuthorDate: Thu Jul 9 05:34:24 2026 +0900
feat: Add SLMP (MELSEC Communication 3E) protocol module (read-only wire
layer) (#2597)
* feat: Add SLMP (MELSEC Communication 3E) protocol module - read-only wire
layer
Adds the codegen-layer protocol module for SLMP / MELSEC Communication
protocol (Mitsubishi PLCs), as proposed in the SLMP driver proposal issue:
- slmp.mspec modelling the 3E binary frame (request/response), with
Batch Read (0x0401), Random Read (0x0403) and Batch Read Multiple
Blocks (0x0406) in word units, read-only
- ParserSerializer test suite with vectors derived from the worked
examples in the public Mitsubishi reference manual SH-080008
(sections 8.1/8.3/8.4)
- Root type declares the new-SPI encoding defaults (little-endian)
The driver module (plc4j/drivers/slmp) will follow on top of the new
SPI as a separate step.
Signed-off-by: Jooyoung Jung <[email protected]>
* fix(slmp): use canonical enum form for deviceCode in test vectors
deviceCode is a numeric enum (SlmpDeviceCode), but the ParserSerializer
test vectors used the shorthand <deviceCode>D</deviceCode> form. That
does not round-trip through the generated parser/serializer, which
expects the full enum element with its numeric value:
<deviceCode>
<SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="D">168</SlmpDeviceCode>
</deviceCode>
Convert all deviceCode occurrences in ParserSerializerTestsuite.xml to
the canonical form so the vectors round-trip once the generated driver
types exercise them.
---------
Signed-off-by: Jooyoung Jung <[email protected]>
---
protocols/pom.xml | 1 +
protocols/slmp/pom.xml | 53 ++++
.../apache/plc4x/protocol/slmp/SlmpProtocol.java | 42 ++++
...e.plc4x.plugins.codegenerator.protocol.Protocol | 19 ++
.../src/main/resources/protocols/slmp/slmp.mspec | 167 ++++++++++++
.../plc4x/protocol/slmp/SlmpProtocolTest.java | 37 +++
protocols/slmp/src/test/resources/logback-test.xml | 36 +++
.../protocols/slmp/ParserSerializerTestsuite.xml | 279 +++++++++++++++++++++
8 files changed, 634 insertions(+)
diff --git a/protocols/pom.xml b/protocols/pom.xml
index aef6e7a883..07c5fa1003 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -59,6 +59,7 @@
<module>profinet</module>
<module>s7</module>
<module>simulated</module>
+ <module>slmp</module>
<module>socketcan</module>
<module>umas</module>
</modules>
diff --git a/protocols/slmp/pom.xml b/protocols/slmp/pom.xml
new file mode 100644
index 0000000000..91ebbc3b34
--- /dev/null
+++ b/protocols/slmp/pom.xml
@@ -0,0 +1,53 @@
+<?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
+
+ 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.
+ -->
+<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.14.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>plc4x-protocols-slmp</artifactId>
+
+ <name>Protocols: SLMP</name>
+ <description>Base protocol specifications for the SLMP / MELSEC
Communication protocol</description>
+
+ <properties>
+
<project.build.outputTimestamp>2025-08-02T13:55:11Z</project.build.outputTimestamp>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-base-mspec</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git
a/protocols/slmp/src/main/java/org/apache/plc4x/protocol/slmp/SlmpProtocol.java
b/protocols/slmp/src/main/java/org/apache/plc4x/protocol/slmp/SlmpProtocol.java
new file mode 100644
index 0000000000..2c8959c98f
--- /dev/null
+++
b/protocols/slmp/src/main/java/org/apache/plc4x/protocol/slmp/SlmpProtocol.java
@@ -0,0 +1,42 @@
+/*
+ * 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.protocol.slmp;
+
+import
org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import
org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ProtocolHelpers;
+import
org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
+import
org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+public class SlmpProtocol implements Protocol, ProtocolHelpers {
+
+ @Override
+ public String getName() {
+ return "slmp";
+ }
+
+ @Override
+ public TypeContext getTypeContext() throws GenerationException {
+ ValidatableTypeContext typeContext = new
MessageFormatParser().parse(getMspecStream());
+ typeContext.validate();
+ return typeContext;
+ }
+
+}
diff --git
a/protocols/slmp/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
b/protocols/slmp/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000000..2195c2e214
--- /dev/null
+++
b/protocols/slmp/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
+#
+# 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.
+#
+org.apache.plc4x.protocol.slmp.SlmpProtocol
diff --git a/protocols/slmp/src/main/resources/protocols/slmp/slmp.mspec
b/protocols/slmp/src/main/resources/protocols/slmp/slmp.mspec
new file mode 100644
index 0000000000..20170095ae
--- /dev/null
+++ b/protocols/slmp/src/main/resources/protocols/slmp/slmp.mspec
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+// SLMP (Seamless Message Protocol) / MELSEC Communication protocol.
+//
+// Specification: Mitsubishi "MELSEC Communication Protocol Reference Manual"
+// (SH(NA)-080008, public). All field layouts below are taken from that
manual:
+// - 3E frame message format ....... section 5.2
+// - Subheader (50 00 / D0 00) ...... section 5.3
+// - Access route (3E fixed value) .. chapter 6
+// - Request/response data length ... section 5.3 (2-byte, little-endian)
+// - Commands (Batch/Random/block Read) chapter 7 / 8.1 / 8.3 / 8.4
+// - Device code list ............... section 8.1 (MELSEC-Q/L, 1-byte
binary)
+// - Batch Read data layout ......... section 8.1 (binary, word units)
+// - Random Read data layout ........ section 8.3 (binary, word units)
+// - Multi-block Read data layout ... section 8.4 (binary, word units)
+//
+// Scope of this initial version: 3E binary frame, read-only, Batch Read
+// (command 0x0401), Random Read (command 0x0403) and Batch Read Multiple
Blocks
+// (command 0x0406) in word units (subcommand 0x0000). This is the wire layer
+// only; typed value decoding
+// (INT/WORD/DINT/REAL) and the device-addressing tag layer are intentionally
+// NOT modelled here yet and will follow once the driver logic is built.
+// Validated hardware-free via the ParserSerializer test suite.
+//
+// All multi-byte numeric fields are little-endian (transmitted
least-significant byte first).
+// The 2-byte subheader (0x50/0xD0 then 0x00) is modelled as two single bytes
so
+// its on-wire order is preserved regardless of the frame byte order.
+
+[constants
+ // Typical SLMP TCP port; the actual port is configured on the device and
is
+ // overridable by the driver, so this is only a default.
+ [const uint 16 slmpDefaultPort 5007]
+]
+
+// Device codes for MELSEC-Q/L series commands (subcommand 0x0000 / 0x0001),
+// 1-byte binary, from the device code list in SH-080008 section 8.1.
+// Only the word/bit devices needed by the read-only road-map are listed.
+//
+// These 1-byte binary device codes are confirmed identical in the Mitsubishi
+// MELSEC iQ-F FX5 SLMP manual (JY997D56001) -- D=A8 W=B4 R=AF M=90 X=9C Y=9D
+// B=A0 -- so the same frame works on FX5 hardware (e.g. FX5S) as well as
+// MELSEC-Q/L. (FX5 also offers a 2-byte/extended code form via subcommand
+// 0x0002/0x0003 for ZR and large device numbers, which is out of scope here.)
+[enum uint 8 SlmpDeviceCode
+ ['0xA8' D] // Data register (word, decimal addressing)
+ ['0xB4' W] // Link register (word, hex addressing)
+ ['0xAF' R] // File register (word, decimal addressing)
+ ['0xC2' TN] // Timer, current value (word, decimal addressing) -- used by
the
+ // Random Read worked example in SH-080008 section 8.3
+ ['0x90' M] // Internal relay (bit, decimal addressing)
+ ['0x9C' X] // Input (bit, hex addressing)
+ ['0x9D' Y] // Output (bit, hex addressing)
+ ['0xA0' B] // Link relay (bit, hex addressing)
+]
+
+// 3E frame. The Ethernet/TCP header is added by the transport and is not part
+// of this message. Request and response are distinguished by the subheader
byte
+// (0x50 request / 0xD0 response).
+[discriminatedType SlmpMessage byteOrder='"LITTLE_ENDIAN"'
unsignedIntegerEncoding='"unsigned-binary"'
signedIntegerEncoding='"twos-complement"' floatEncoding='"IEEE754"'
stringEncoding='"UTF8"'
+ [discriminator uint 8 subHeader] // 0x50 request, 0xD0
response
+ [const uint 8 subHeaderReserved 0x00] // second subheader byte
is always 0x00
+ [typeSwitch subHeader
+ ['0x50' SlmpRequestFrame3E
+ // Access route - fixed value for 3E frame (chapter 6): 00 FF FF
03 00
+ [const uint 8 network 0x00]
+ [const uint 8 pcNumber 0xFF]
+ [const uint 16 requestDestModuleIoNo 0x03FF]
+ [const uint 8 requestDestModuleStation 0x00]
+ // Number of bytes from the monitoring timer up to the end of the
request data.
+ // = monitoringTimer(2) + command(2) + subCommand(2) + requestData
+ [implicit uint 16 requestDataLength '6 +
requestData.lengthInBytes']
+ [simple uint 16 monitoringTimer] // 0x0000 =
wait infinitely
+ [simple uint 16 command] // 0x0401 =
Batch Read
+ [simple uint 16 subCommand] // 0x0000 =
word units
+ [simple SlmpRequestData('command') requestData]
+ ]
+ ['0xD0' SlmpResponseFrame3E
+ [const uint 8 network 0x00]
+ [const uint 8 pcNumber 0xFF]
+ [const uint 16 requestDestModuleIoNo 0x03FF]
+ [const uint 8 requestDestModuleStation 0x00]
+ // Number of bytes from the end code up to the end of the response
data.
+ // = endCode(2) + responseData
+ [implicit uint 16 responseDataLength '2 +
COUNT(responseData)']
+ [simple uint 16 endCode] // 0x0000 =
normal completion
+ // Raw payload. On normal completion this is the read words
(little-endian,
+ // 2 bytes per point); on abnormal completion it carries error
information.
+ // Typed decoding is left to the driver layer.
+ [array byte responseData count
'responseDataLength - 2']
+ ]
+ ]
+]
+
+// Request data, dispatched by command. Batch Read (0x0401) and Random Read
+// (0x0403) are modelled here; both are read-only, word units (subcommand
0x0000).
+[discriminatedType SlmpRequestData(uint 16 command)
+ [typeSwitch command
+ ['0x0401' SlmpReadRequest
+ // Binary, MELSEC-Q/L series: device number (3 bytes,
little-endian)
+ // then device code (1 byte). See SH-080008 section 8.1.
+ [simple uint 24 headDeviceNumber]
+ [simple SlmpDeviceCode deviceCode]
+ // Number of points to read. In word units this is the number of
16-bit words.
+ [simple uint 16 numberOfPoints]
+ ]
+ ['0x0403' SlmpRandomReadRequest
+ // Random Read in word units (SH-080008 section 8.3): read
discontinuous
+ // devices, given as a list of word-access points followed by a
list of
+ // double-word-access points. The point counts are single bytes;
each
+ // device is a 3-byte device number + 1-byte device code
(SlmpDeviceSpec).
+ [simple uint 8 numberOfWordAccessPoints]
+ [simple uint 8 numberOfDoubleWordAccessPoints]
+ [array SlmpDeviceSpec wordAccessDevices count
'numberOfWordAccessPoints']
+ [array SlmpDeviceSpec doubleWordAccessDevices count
'numberOfDoubleWordAccessPoints']
+ ]
+ ['0x0406' SlmpMultiBlockReadRequest
+ // Batch Read multiple blocks in word units (SH-080008 section
8.4): read a
+ // number of word-device blocks followed by a number of bit-device
blocks,
+ // where each block is a run of consecutive devices. The two block
counts are
+ // single bytes; each block (SlmpDeviceBlock) is a 3-byte head
device number,
+ // a 1-byte device code and a 2-byte number of points. Bit-device
blocks are
+ // read in 16-bit word units (one point = 16 bits), so the wire
layout of a
+ // bit-device block is identical to that of a word-device block.
+ [simple uint 8 numberOfWordDeviceBlocks]
+ [simple uint 8 numberOfBitDeviceBlocks]
+ [array SlmpDeviceBlock wordDeviceBlocks count
'numberOfWordDeviceBlocks']
+ [array SlmpDeviceBlock bitDeviceBlocks count
'numberOfBitDeviceBlocks']
+ ]
+ ]
+]
+
+// A single device specification used by commands that address discontinuous
+// devices (e.g. Random Read 0x0403): a device number (3 bytes, little-endian)
+// followed by the 1-byte device code. See SH-080008 section 8.1 / 8.3.
+[type SlmpDeviceSpec
+ [simple uint 24 deviceNumber]
+ [simple SlmpDeviceCode deviceCode]
+]
+
+// A single block of consecutive devices used by commands that read whole
blocks
+// (e.g. Batch Read Multiple Blocks 0x0406): a head device number (3 bytes,
+// little-endian) and 1-byte device code identifying the start of the run,
+// followed by the 2-byte number of points (consecutive devices) in the block.
+// This is the same field layout as a single-block Batch Read request
+// (SlmpReadRequest). See SH-080008 section 8.4.
+[type SlmpDeviceBlock
+ [simple uint 24 headDeviceNumber]
+ [simple SlmpDeviceCode deviceCode]
+ [simple uint 16 numberOfPoints]
+]
diff --git
a/protocols/slmp/src/test/java/org/apache/plc4x/protocol/slmp/SlmpProtocolTest.java
b/protocols/slmp/src/test/java/org/apache/plc4x/protocol/slmp/SlmpProtocolTest.java
new file mode 100644
index 0000000000..06f0b490ec
--- /dev/null
+++
b/protocols/slmp/src/test/java/org/apache/plc4x/protocol/slmp/SlmpProtocolTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.protocol.slmp;
+
+import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+class SlmpProtocolTest {
+
+ @Test
+ void getTypeContext() throws Exception {
+ TypeContext typeContext = new SlmpProtocol().getTypeContext();
+ assertNotNull(typeContext);
+ assertNotNull(typeContext.getUnresolvedTypeReferences());
+ assertSame(0, typeContext.getUnresolvedTypeReferences().size());
+ }
+
+}
diff --git a/protocols/slmp/src/test/resources/logback-test.xml
b/protocols/slmp/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..0524f110fc
--- /dev/null
+++ b/protocols/slmp/src/test/resources/logback-test.xml
@@ -0,0 +1,36 @@
+<?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
+
+ 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.
+ -->
+<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://ch.qos.logback/xml/ns/logback
+
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
%msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="error">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
diff --git
a/protocols/slmp/src/test/resources/protocols/slmp/ParserSerializerTestsuite.xml
b/protocols/slmp/src/test/resources/protocols/slmp/ParserSerializerTestsuite.xml
new file mode 100644
index 0000000000..6054c1963b
--- /dev/null
+++
b/protocols/slmp/src/test/resources/protocols/slmp/ParserSerializerTestsuite.xml
@@ -0,0 +1,279 @@
+<?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
+
+ 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.
+ -->
+<!--
+ Reference vectors derived from the worked examples in the Mitsubishi MELSEC
+ Communication Protocol Reference Manual (SH-080008). The full 3E binary frame
+ is assembled per section 5.2 / chapter 6.
+
+ Batch Read (0x0401) word-unit example reading the values stored in D350 and
+ D351 (section 8.1):
+ request data : 5E 01 00 A8 02 00 (head=D350, code=D, points=2)
+ response data: AB 56 0F 17 (D350=0x56AB, D351=0x170F)
+
+ Random Read (0x0403) word-unit example reading D0, T0, M100, X20 in word
units
+ and D1500, Y160, M1111 in double-word units (section 8.3):
+ request data : 04 03 (4 word pts,
3 dword pts)
+ 00 00 00 A8 00 00 00 C2 64 00 00 90 20 00 00 9C (D0,
T0, M100, X20)
+ DC 05 00 A8 60 01 00 9D 57 04 00 90 (D1500,
Y160, M1111)
+ response data: 95 19 02 12 30 20 49 48
(D0=0x1995, T0=0x1202, ...)
+ 4E 4F 54 4C AF B9 DE C3 B7 BC DD BA
(D1500/01=0x4F4E/0x4C54, ...)
+
+ Batch Read Multiple Blocks (0x0406) word-unit example reading two word-device
+ blocks (D0-D3, W100-W107) and three bit-device blocks (M0-M31, M128-M159,
+ B100-B12F), section 8.4:
+ request data : 02 03 (2 word blocks, 3 bit
blocks)
+ 00 00 00 A8 04 00 (block D0, 4 points)
+ 00 01 00 B4 08 00 (block W100, 8 points)
+ 00 00 00 90 02 00 (block M0, 2 points)
+ 80 00 00 90 02 00 (block M128, 2 points)
+ 00 01 00 A0 03 00 (block B100, 3 points)
+ The response (per the manual: word-block data then bit-block data, 16 bits
per
+ point) re-uses the generic SlmpResponseFrame3E raw-byte payload already
covered
+ by the Batch/Random Read response cases above, so it is not duplicated here.
+ -->
+<test:testsuite
xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd"
+ byteOrder="LITTLE_ENDIAN">
+
+ <name>SLMP</name>
+
+ <protocol-name>slmp</protocol-name>
+ <output-flavor>read-write</output-flavor>
+
+ <testcase>
+ <name>3E Batch Read Request - D350, 2 words</name>
+ <raw>500000ffff03000c000000010400005e0100a80200</raw>
+ <root-type>SlmpMessage</root-type>
+ <xml>
+ <SlmpMessage>
+ <subHeader dataType="uint" bitLength="8">80</subHeader>
+ <subHeaderReserved dataType="uint" bitLength="8">0</subHeaderReserved>
+ <SlmpRequestFrame3E>
+ <network dataType="uint" bitLength="8">0</network>
+ <pcNumber dataType="uint" bitLength="8">255</pcNumber>
+ <requestDestModuleIoNo dataType="uint"
bitLength="16">1023</requestDestModuleIoNo>
+ <requestDestModuleStation dataType="uint"
bitLength="8">0</requestDestModuleStation>
+ <requestDataLength dataType="uint"
bitLength="16">12</requestDataLength>
+ <monitoringTimer dataType="uint" bitLength="16">0</monitoringTimer>
+ <command dataType="uint" bitLength="16">1025</command>
+ <subCommand dataType="uint" bitLength="16">0</subCommand>
+ <requestData>
+ <SlmpRequestData>
+ <SlmpReadRequest>
+ <headDeviceNumber dataType="uint"
bitLength="24">350</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="D">168</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">2</numberOfPoints>
+ </SlmpReadRequest>
+ </SlmpRequestData>
+ </requestData>
+ </SlmpRequestFrame3E>
+ </SlmpMessage>
+ </xml>
+ </testcase>
+
+ <testcase>
+ <name>3E Batch Read Response - D350=0x56AB, D351=0x170F</name>
+ <raw>d00000ffff030006000000ab560f17</raw>
+ <root-type>SlmpMessage</root-type>
+ <xml>
+ <SlmpMessage>
+ <subHeader dataType="uint" bitLength="8">208</subHeader>
+ <subHeaderReserved dataType="uint" bitLength="8">0</subHeaderReserved>
+ <SlmpResponseFrame3E>
+ <network dataType="uint" bitLength="8">0</network>
+ <pcNumber dataType="uint" bitLength="8">255</pcNumber>
+ <requestDestModuleIoNo dataType="uint"
bitLength="16">1023</requestDestModuleIoNo>
+ <requestDestModuleStation dataType="uint"
bitLength="8">0</requestDestModuleStation>
+ <responseDataLength dataType="uint"
bitLength="16">6</responseDataLength>
+ <endCode dataType="uint" bitLength="16">0</endCode>
+ <responseData dataType="byte"
bitLength="32">0xab560f17</responseData>
+ </SlmpResponseFrame3E>
+ </SlmpMessage>
+ </xml>
+ </testcase>
+
+ <testcase>
+ <name>3E Random Read Request - D0,T0,M100,X20 word + D1500,Y160,M1111
dword</name>
+
<raw>500000ffff030024000000030400000403000000a8000000c2640000902000009cdc0500a86001009d57040090</raw>
+ <root-type>SlmpMessage</root-type>
+ <xml>
+ <SlmpMessage>
+ <subHeader dataType="uint" bitLength="8">80</subHeader>
+ <subHeaderReserved dataType="uint" bitLength="8">0</subHeaderReserved>
+ <SlmpRequestFrame3E>
+ <network dataType="uint" bitLength="8">0</network>
+ <pcNumber dataType="uint" bitLength="8">255</pcNumber>
+ <requestDestModuleIoNo dataType="uint"
bitLength="16">1023</requestDestModuleIoNo>
+ <requestDestModuleStation dataType="uint"
bitLength="8">0</requestDestModuleStation>
+ <requestDataLength dataType="uint"
bitLength="16">36</requestDataLength>
+ <monitoringTimer dataType="uint" bitLength="16">0</monitoringTimer>
+ <command dataType="uint" bitLength="16">1027</command>
+ <subCommand dataType="uint" bitLength="16">0</subCommand>
+ <requestData>
+ <SlmpRequestData>
+ <SlmpRandomReadRequest>
+ <numberOfWordAccessPoints dataType="uint"
bitLength="8">4</numberOfWordAccessPoints>
+ <numberOfDoubleWordAccessPoints dataType="uint"
bitLength="8">3</numberOfDoubleWordAccessPoints>
+ <wordAccessDevices isList="true">
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">0</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="D">168</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">0</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="TN">194</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">100</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="M">144</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">32</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="X">156</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ </wordAccessDevices>
+ <doubleWordAccessDevices isList="true">
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">1500</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="D">168</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">352</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="Y">157</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ <SlmpDeviceSpec>
+ <deviceNumber dataType="uint"
bitLength="24">1111</deviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="M">144</SlmpDeviceCode>
+ </deviceCode>
+ </SlmpDeviceSpec>
+ </doubleWordAccessDevices>
+ </SlmpRandomReadRequest>
+ </SlmpRequestData>
+ </requestData>
+ </SlmpRequestFrame3E>
+ </SlmpMessage>
+ </xml>
+ </testcase>
+
+ <testcase>
+ <name>3E Random Read Response - 4 word + 3 dword values</name>
+ <raw>d00000ffff03001600000095190212302049484e4f544cafb9dec3b7bcddba</raw>
+ <root-type>SlmpMessage</root-type>
+ <xml>
+ <SlmpMessage>
+ <subHeader dataType="uint" bitLength="8">208</subHeader>
+ <subHeaderReserved dataType="uint" bitLength="8">0</subHeaderReserved>
+ <SlmpResponseFrame3E>
+ <network dataType="uint" bitLength="8">0</network>
+ <pcNumber dataType="uint" bitLength="8">255</pcNumber>
+ <requestDestModuleIoNo dataType="uint"
bitLength="16">1023</requestDestModuleIoNo>
+ <requestDestModuleStation dataType="uint"
bitLength="8">0</requestDestModuleStation>
+ <responseDataLength dataType="uint"
bitLength="16">22</responseDataLength>
+ <endCode dataType="uint" bitLength="16">0</endCode>
+ <responseData dataType="byte"
bitLength="160">0x95190212302049484e4f544cafb9dec3b7bcddba</responseData>
+ </SlmpResponseFrame3E>
+ </SlmpMessage>
+ </xml>
+ </testcase>
+
+ <testcase>
+ <name>3E Multi-block Read Request - 2 word blocks (D0-D3, W100-W107) + 3
bit blocks (M0-M31, M128-M159, B100-B12F)</name>
+
<raw>500000ffff030026000000060400000203000000a80400000100b40800000000900200800000900200000100a00300</raw>
+ <root-type>SlmpMessage</root-type>
+ <xml>
+ <SlmpMessage>
+ <subHeader dataType="uint" bitLength="8">80</subHeader>
+ <subHeaderReserved dataType="uint" bitLength="8">0</subHeaderReserved>
+ <SlmpRequestFrame3E>
+ <network dataType="uint" bitLength="8">0</network>
+ <pcNumber dataType="uint" bitLength="8">255</pcNumber>
+ <requestDestModuleIoNo dataType="uint"
bitLength="16">1023</requestDestModuleIoNo>
+ <requestDestModuleStation dataType="uint"
bitLength="8">0</requestDestModuleStation>
+ <requestDataLength dataType="uint"
bitLength="16">38</requestDataLength>
+ <monitoringTimer dataType="uint" bitLength="16">0</monitoringTimer>
+ <command dataType="uint" bitLength="16">1030</command>
+ <subCommand dataType="uint" bitLength="16">0</subCommand>
+ <requestData>
+ <SlmpRequestData>
+ <SlmpMultiBlockReadRequest>
+ <numberOfWordDeviceBlocks dataType="uint"
bitLength="8">2</numberOfWordDeviceBlocks>
+ <numberOfBitDeviceBlocks dataType="uint"
bitLength="8">3</numberOfBitDeviceBlocks>
+ <wordDeviceBlocks isList="true">
+ <SlmpDeviceBlock>
+ <headDeviceNumber dataType="uint"
bitLength="24">0</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="D">168</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">4</numberOfPoints>
+ </SlmpDeviceBlock>
+ <SlmpDeviceBlock>
+ <headDeviceNumber dataType="uint"
bitLength="24">256</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="W">180</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">8</numberOfPoints>
+ </SlmpDeviceBlock>
+ </wordDeviceBlocks>
+ <bitDeviceBlocks isList="true">
+ <SlmpDeviceBlock>
+ <headDeviceNumber dataType="uint"
bitLength="24">0</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="M">144</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">2</numberOfPoints>
+ </SlmpDeviceBlock>
+ <SlmpDeviceBlock>
+ <headDeviceNumber dataType="uint"
bitLength="24">128</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="M">144</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">2</numberOfPoints>
+ </SlmpDeviceBlock>
+ <SlmpDeviceBlock>
+ <headDeviceNumber dataType="uint"
bitLength="24">256</headDeviceNumber>
+ <deviceCode>
+ <SlmpDeviceCode dataType="uint" bitLength="8"
stringRepresentation="B">160</SlmpDeviceCode>
+ </deviceCode>
+ <numberOfPoints dataType="uint"
bitLength="16">3</numberOfPoints>
+ </SlmpDeviceBlock>
+ </bitDeviceBlocks>
+ </SlmpMultiBlockReadRequest>
+ </SlmpRequestData>
+ </requestData>
+ </SlmpRequestFrame3E>
+ </SlmpMessage>
+ </xml>
+ </testcase>
+
+</test:testsuite>