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/02/13 15:15:46 UTC
[plc4x] 01/02: - Got the new Modbus driver to actually do something.
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
commit 53b1d49484c394674e757367f59e83105ecb55ef
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Feb 13 16:14:59 2020 +0100
- Got the new Modbus driver to actually do something.
---
.../org/apache/plc4x/java/api/value/PlcByte.java | 156 +++++++++++++++++++++
.../org/apache/plc4x/java/api/value/PlcList.java | 2 +-
.../org/apache/plc4x/java/api/value/PlcShort.java | 156 +++++++++++++++++++++
.../utils/rawsockets/netty/RawSocketChannel.java | 4 +-
.../main/resources/protocols/modbus/modbus.mspec | 21 ++-
.../org/apache/plc4x/java/modbus/ModbusDriver.java | 11 +-
.../plc4x/java/modbus/field/ModbusField.java | 2 +-
.../modbus/field/ModbusFieldDiscreteInput.java | 2 +-
.../modbus/field/ModbusFieldHoldingRegister.java | 2 +-
.../modbus/field/ModbusFieldInputRegister.java | 2 +-
.../modbus/field/ModbusFieldMaskWriteRegister.java | 2 +-
.../java/modbus/protocol/ModbusProtocolLogic.java | 92 +++++++++++-
12 files changed, 437 insertions(+), 15 deletions(-)
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcByte.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcByte.java
new file mode 100644
index 0000000..35eaefa
--- /dev/null
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcByte.java
@@ -0,0 +1,156 @@
+/*
+ * 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.api.value;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class PlcByte extends PlcSimpleValue<Byte> {
+
+ public PlcByte(Byte value) {
+ super(value, true);
+ }
+
+ public PlcByte(byte value) {
+ super(value, false);
+ }
+
+ public PlcByte(Short value) {
+ super(value.byteValue(), true);
+ }
+
+ public PlcByte(short value) {
+ super(((Short) value).byteValue(), false);
+ }
+
+ public PlcByte(Integer value) {
+ super(value.byteValue(), true);
+ }
+
+ public PlcByte(int value) {
+ super(((Integer) value).byteValue(), false);
+ }
+
+ @Override
+ public boolean isBoolean() {
+ return true;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return (value != null) && !value.equals((byte) 0);
+ }
+
+ @Override
+ public boolean isByte() {
+ return true;
+ }
+
+ @Override
+ public byte getByte() {
+ return value;
+ }
+
+ @Override
+ public boolean isShort() {
+ return true;
+ }
+
+ @Override
+ public short getShort() {
+ return value.shortValue();
+ }
+
+ @Override
+ public boolean isInteger() {
+ return true;
+ }
+
+ @Override
+ public int getInteger() {
+ return value.intValue();
+ }
+
+ @Override
+ public boolean isLong() {
+ return true;
+ }
+
+ @Override
+ public long getLong() {
+ return value.longValue();
+ }
+
+ @Override
+ public boolean isBigInteger() {
+ return true;
+ }
+
+ @Override
+ public BigInteger getBigInteger() {
+ return BigInteger.valueOf((long) value);
+ }
+
+ @Override
+ public boolean isFloat() {
+ return true;
+ }
+
+ @Override
+ public float getFloat() {
+ return value.floatValue();
+ }
+
+ @Override
+ public boolean isDouble() {
+ return true;
+ }
+
+ @Override
+ public double getDouble() {
+ return value.doubleValue();
+ }
+
+ @Override
+ public boolean isBigDecimal() {
+ return true;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal() {
+ return new BigDecimal(value);
+ }
+
+ @Override
+ public boolean isString() {
+ return true;
+ }
+
+ @Override
+ public String getString() {
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+
+}
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
index 1cfb684..1218a2a 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcList.java
@@ -31,7 +31,7 @@ public class PlcList extends PlcValueAdapter {
List<PlcValue> safelist = listItems.stream().map(plcValue -> {
// to avoid unwrapped list cause of type erasure
if (plcValue instanceof PlcValue) {
- return (PlcValue)plcValue;
+ return (PlcValue) plcValue;
} else {
return PlcValues.of(plcValue);
}
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcShort.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcShort.java
new file mode 100644
index 0000000..5e93c8e
--- /dev/null
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcShort.java
@@ -0,0 +1,156 @@
+/*
+ * 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.api.value;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class PlcShort extends PlcSimpleValue<Short> {
+
+ public PlcShort(Byte value) {
+ super(value.shortValue(), true);
+ }
+
+ public PlcShort(byte value) {
+ super(((Byte) value).shortValue(), false);
+ }
+
+ public PlcShort(Short value) {
+ super(value, true);
+ }
+
+ public PlcShort(short value) {
+ super(value, false);
+ }
+
+ public PlcShort(Integer value) {
+ super(value.shortValue(), true);
+ }
+
+ public PlcShort(int value) {
+ super(((Integer) value).shortValue(), false);
+ }
+
+ @Override
+ public boolean isBoolean() {
+ return true;
+ }
+
+ @Override
+ public boolean getBoolean() {
+ return (value != null) && !value.equals((short) 0);
+ }
+
+ @Override
+ public boolean isByte() {
+ return true;
+ }
+
+ @Override
+ public byte getByte() {
+ return value.byteValue();
+ }
+
+ @Override
+ public boolean isShort() {
+ return true;
+ }
+
+ @Override
+ public short getShort() {
+ return value;
+ }
+
+ @Override
+ public boolean isInteger() {
+ return true;
+ }
+
+ @Override
+ public int getInteger() {
+ return value.intValue();
+ }
+
+ @Override
+ public boolean isLong() {
+ return true;
+ }
+
+ @Override
+ public long getLong() {
+ return value.longValue();
+ }
+
+ @Override
+ public boolean isBigInteger() {
+ return true;
+ }
+
+ @Override
+ public BigInteger getBigInteger() {
+ return BigInteger.valueOf((long) value);
+ }
+
+ @Override
+ public boolean isFloat() {
+ return true;
+ }
+
+ @Override
+ public float getFloat() {
+ return value.floatValue();
+ }
+
+ @Override
+ public boolean isDouble() {
+ return true;
+ }
+
+ @Override
+ public double getDouble() {
+ return value.doubleValue();
+ }
+
+ @Override
+ public boolean isBigDecimal() {
+ return true;
+ }
+
+ @Override
+ public BigDecimal getBigDecimal() {
+ return new BigDecimal(value);
+ }
+
+ @Override
+ public boolean isString() {
+ return true;
+ }
+
+ @Override
+ public String getString() {
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+
+}
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
index 2e1b8d8..386a033 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java
@@ -84,9 +84,9 @@ public class RawSocketChannel extends OioByteStreamChannel {
// Try to get the device name of the network interface that we want to open.
String deviceName = getDeviceName(remoteRawSocketAddress);
if(deviceName == null) {
- logger.error("Network device not specified and coudln't detect it automatically");
+ logger.error("Network device not specified and couldn't detect it automatically");
pipeline().fireExceptionCaught(
- new RawSocketException("Network device not specified and coudln't detect it automatically"));
+ new RawSocketException("Network device not specified and couldn't detect it automatically"));
return;
}
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index 6347dda..24f41a8 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -56,8 +56,8 @@
]
[discriminatedType 'ModbusPDU' [bit 'response']
- [implicit uint 7 'function' 'DISCRIMINATOR_VALUES[1]']
[implicit bit 'error' 'DISCRIMINATOR_VALUES[0]']
+ [implicit uint 7 'function' 'DISCRIMINATOR_VALUES[1]']
[typeSwitch 'error','function','response'
['true' ModbusPDUError
[simple uint 8 'exceptionCode']
@@ -267,3 +267,22 @@
[implicit uint 16 'recordLength' '(COUNT(recordData) * 2) / 2']
[array uint 16 'recordData' length 'recordLength * 2']
]
+
+[dataIo 'DataItem' [uint 8 'dataType', uint 8 'numberOfValues']
+ [typeSwitch 'dataType','numberOfValues'
+ ['1','1' Boolean
+ [reserved uint 7 '0x00']
+ [simple bit 'value']
+ ]
+ ['1' List
+ [array bit 'value' count 'numberOfValues']
+ ]
+ ['2','1' Integer
+ [simple int 16 'value']
+ ]
+ ['2' List
+ [array int 16 'value' count 'numberOfValues']
+ ]
+ ]
+]
+
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
index 9a2a6f3..6000572 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/ModbusDriver.java
@@ -56,6 +56,15 @@ public class ModbusDriver extends GeneratedDriverBase<ModbusTcpADU> {
return "tcp";
}
+ /**
+ * Modbus doesn't have a login procedure, so there is no need to wait for a login to finish.
+ * @return false
+ */
+ @Override
+ protected boolean awaitSetupComplete() {
+ return false;
+ }
+
@Override
protected boolean canRead() {
return true;
@@ -86,7 +95,7 @@ public class ModbusDriver extends GeneratedDriverBase<ModbusTcpADU> {
@Override
public int applyAsInt(ByteBuf byteBuf) {
if (byteBuf.readableBytes() >= 6) {
- return byteBuf.getUnsignedShort(byteBuf.readerIndex() + 4);
+ return byteBuf.getUnsignedShort(byteBuf.readerIndex() + 4) + 6;
}
return -1;
}
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
index 1752d77..2edce00 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public abstract class ModbusField implements PlcField {
- public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?<address>\\d+)(\\[(?<quantity>\\d)])?");
+ public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?<address>\\d+)(\\[(?<quantity>\\d+)])?");
private final int address;
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
index 0ccdbf5..5f35670 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldDiscreteInput.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public class ModbusFieldDiscreteInput extends ModbusField {
- public static final Pattern ADDRESS_PATTERN = Pattern.compile("readdiscreteinputs:" + ModbusField.ADDRESS_PATTERN);
+ public static final Pattern ADDRESS_PATTERN = Pattern.compile("discrete-input:" + ModbusField.ADDRESS_PATTERN);
public ModbusFieldDiscreteInput(int address, Integer quantity) {
super(address, quantity);
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
index 7d2cba3..a720cac 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHoldingRegister.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public class ModbusFieldHoldingRegister extends ModbusField {
- public static final Pattern ADDRESS_PATTERN = Pattern.compile("readholdingregisters:" + ModbusField.ADDRESS_PATTERN);
+ public static final Pattern ADDRESS_PATTERN = Pattern.compile("holding-register:" + ModbusField.ADDRESS_PATTERN);
protected ModbusFieldHoldingRegister(int address, Integer quantity) {
super(address, quantity);
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
index 1185554..6dc0016 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldInputRegister.java
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public class ModbusFieldInputRegister extends ModbusField {
- public static final Pattern ADDRESS_PATTERN = Pattern.compile("readinputregisters:" + ModbusField.ADDRESS_PATTERN);
+ public static final Pattern ADDRESS_PATTERN = Pattern.compile("input-register:" + ModbusField.ADDRESS_PATTERN);
protected ModbusFieldInputRegister(int address, Integer quantity) {
super(address, quantity);
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
index 5ad9f09..7c3d513 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldMaskWriteRegister.java
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
@Deprecated
public class ModbusFieldMaskWriteRegister extends ModbusField {
- public static final Pattern ADDRESS_PATTERN = Pattern.compile("maskwrite:" + ModbusField.ADDRESS_PATTERN + "/" + "(?<andMask>\\d+)/(?<orMask>\\d+)");
+ public static final Pattern ADDRESS_PATTERN = Pattern.compile("mask-write:" + ModbusField.ADDRESS_PATTERN + "/" + "(?<andMask>\\d+)/(?<orMask>\\d+)");
private final int andMask;
private final int orMask;
diff --git a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
index 796c542..4beef07 100644
--- a/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
+++ b/sandbox/test-java-modbus-driver/src/main/java/org/apache/plc4x/java/modbus/protocol/ModbusProtocolLogic.java
@@ -18,24 +18,38 @@ under the License.
*/
package org.apache.plc4x.java.modbus.protocol;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
import org.apache.plc4x.java.api.messages.PlcReadRequest;
import org.apache.plc4x.java.api.messages.PlcReadResponse;
import org.apache.plc4x.java.api.messages.PlcWriteRequest;
import org.apache.plc4x.java.api.messages.PlcWriteResponse;
import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.api.value.PlcBoolean;
+import org.apache.plc4x.java.api.value.PlcList;
+import org.apache.plc4x.java.api.value.PlcValue;
import org.apache.plc4x.java.modbus.config.ModbusConfiguration;
import org.apache.plc4x.java.modbus.field.ModbusFieldCoil;
import org.apache.plc4x.java.modbus.field.ModbusFieldDiscreteInput;
import org.apache.plc4x.java.modbus.field.ModbusFieldHoldingRegister;
import org.apache.plc4x.java.modbus.field.ModbusFieldInputRegister;
import org.apache.plc4x.java.modbus.readwrite.*;
+import org.apache.plc4x.java.modbus.readwrite.io.DataItemIO;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.Plc4xProtocolBase;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest;
+import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse;
import org.apache.plc4x.java.spi.optimizer.RequestTransactionManager;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
@@ -75,7 +89,8 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> implem
// Example for sending a request ...
// TODO: Break down multiple items into sub-futures that are acknowledged at the end
- for (PlcField field : request.getFields()) {
+ for (String fieldName : request.getFieldNames()) {
+ PlcField field = request.getField(fieldName);
ModbusPDU requestPdu = getRequestPdu(field);
int transactionIdentifier = transactionIdentifierGenerator.getAndIncrement();
ModbusTcpADU modbusTcpADU = new ModbusTcpADU(transactionIdentifier, unitIdentifier, requestPdu);
@@ -86,9 +101,25 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> implem
.onError((p, e) -> future.completeExceptionally(e))
.check(p -> p.getTransactionIdentifier() == transactionIdentifier)
.unwrap(ModbusTcpADU::getPdu)
- .handle(p -> {
- // TODO: Do something sensible with the response ...
- //future.complete(p);
+ .handle(responsePdu -> {
+ // Try to decode the response data based on the corresponding request.
+ PlcValue plcValue = null;
+ PlcResponseCode responseCode;
+ try {
+ plcValue = toPlcValue(requestPdu, responsePdu);
+ responseCode = PlcResponseCode.OK;
+ } catch (ParseException e) {
+ // Add an error response code ...
+ responseCode = PlcResponseCode.INTERNAL_ERROR;
+ }
+
+ // Prepare the response.
+ PlcReadResponse response = new DefaultPlcReadResponse(request,
+ Collections.singletonMap(fieldName, Pair.of(responseCode, plcValue)));
+
+ // Pass the response back to the application.
+ future.complete(response);
+
// Finish the request-transaction.
transaction.endRequest();
}));
@@ -124,7 +155,58 @@ public class ModbusProtocolLogic extends Plc4xProtocolBase<ModbusTcpADU> implem
ModbusFieldHoldingRegister holdingRegister = (ModbusFieldHoldingRegister) field;
return new ModbusPDUReadHoldingRegistersRequest(holdingRegister.getAddress(), holdingRegister.getQuantity());
}
- throw new RuntimeException("Unsupported field type " + field.getClass().getName());
+ throw new PlcRuntimeException("Unsupported field type " + field.getClass().getName());
+ }
+
+ private PlcValue toPlcValue(ModbusPDU request, ModbusPDU response) throws ParseException {
+ if (request instanceof ModbusPDUReadDiscreteInputsRequest) {
+ if (!(response instanceof ModbusPDUReadDiscreteInputsResponse)) {
+ throw new PlcRuntimeException("Unexpected response type ModbusPDUReadDiscreteInputsResponse");
+ }
+ ModbusPDUReadDiscreteInputsRequest req = (ModbusPDUReadDiscreteInputsRequest) request;
+ ModbusPDUReadDiscreteInputsResponse resp = (ModbusPDUReadDiscreteInputsResponse) response;
+ return readBooleanList(req.getQuantity(), resp.getValue());
+ } else if (request instanceof ModbusPDUReadCoilsRequest) {
+ if (!(response instanceof ModbusPDUReadCoilsResponse)) {
+ throw new PlcRuntimeException("Unexpected response type ModbusPDUReadCoilsResponse");
+ }
+ ModbusPDUReadCoilsRequest req = (ModbusPDUReadCoilsRequest) request;
+ ModbusPDUReadCoilsResponse resp = (ModbusPDUReadCoilsResponse) response;
+ return readBooleanList(req.getQuantity(), resp.getValue());
+ } else if (request instanceof ModbusPDUReadInputRegistersRequest) {
+ if (!(response instanceof ModbusPDUReadInputRegistersResponse)) {
+ throw new PlcRuntimeException("Unexpected response type ModbusPDUReadInputRegistersResponse");
+ }
+ ModbusPDUReadInputRegistersRequest req = (ModbusPDUReadInputRegistersRequest) request;
+ ModbusPDUReadInputRegistersResponse resp = (ModbusPDUReadInputRegistersResponse) response;
+ ReadBuffer io = new ReadBuffer(resp.getValue());
+ return DataItemIO.staticParse(io, (short) 2, (short) req.getQuantity());
+ } else if (request instanceof ModbusPDUReadHoldingRegistersRequest) {
+ if (!(response instanceof ModbusPDUReadHoldingRegistersResponse)) {
+ throw new PlcRuntimeException("Unexpected response type ModbusPDUReadHoldingRegistersResponse");
+ }
+ ModbusPDUReadHoldingRegistersRequest req = (ModbusPDUReadHoldingRegistersRequest) request;
+ ModbusPDUReadHoldingRegistersResponse resp = (ModbusPDUReadHoldingRegistersResponse) response;
+ ReadBuffer io = new ReadBuffer(resp.getValue());
+ return DataItemIO.staticParse(io, (short) 2, (short) req.getQuantity());
+ }
+ return null;
+ }
+
+ private PlcValue readBooleanList(int count, byte[] data) throws ParseException {
+ ReadBuffer io = new ReadBuffer(data);
+ if(count == 1) {
+ return DataItemIO.staticParse(io, (short) 1, (short) 1);
+ }
+ // Make sure we read in all the bytes. Unfortunately when requesting 9 bytes
+ // they are ordered like this: 8 7 6 5 4 3 2 1 | 0 0 0 0 0 0 0 9
+ // Luckily it turns out that this is exactly how BitSet parses byte[]
+ BitSet bits = BitSet.valueOf(data);
+ List<PlcBoolean> result = new ArrayList<>(count);
+ for(int i = 0; i < count; i++) {
+ result.add(new PlcBoolean(bits.get(i)));
+ }
+ return new PlcList(result);
}
}