You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@plc4x.apache.org by GitBox <gi...@apache.org> on 2018/10/06 18:25:40 UTC

[GitHub] JulianFeinauer closed pull request #28: Type conversions for default byte array fiel item

JulianFeinauer closed pull request #28: Type conversions for default byte array fiel item
URL: https://github.com/apache/incubator-plc4x/pull/28
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteArrayFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteArrayFieldItem.java
index 4663e4689..078422dd9 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteArrayFieldItem.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteArrayFieldItem.java
@@ -29,14 +29,20 @@ public Object getObject(int index) {
         return getValue(index);
     }
 
+    @Override
     public boolean isValidByteArray(int index) {
         Byte[] value = getValue(index);
         return value != null;
     }
 
+    @Override
     public Byte[] getByteArray(int index) {
         return getValue(index);
     }
 
+    //ToDo: extend conversion methods similar to @see {@link org.apache.plc4x.java.modbus.messages.items.DefaultModbusByteArrayFieldItem}
+
+    //ToDo: implement endianness for correct handling of Byte Arrays at conversion
+
 }
 
diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
index 2a4acca15..7df46a93a 100644
--- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
+++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/FieldItem.java
@@ -185,4 +185,6 @@ public String toString() {
             "values=" + Arrays.toString(values) +
             '}';
     }
+
+    //ToDo Replace returning of null by Exceptions
 }
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java
new file mode 100644
index 000000000..963a493bd
--- /dev/null
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java
@@ -0,0 +1,241 @@
+/*
+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.messages.items;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.plc4x.java.base.messages.items.DefaultByteArrayFieldItem;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * default implementation for DefaultByteArrayFieldItem for Usage within Modbus module
+ * default ByteOrder is set to BIG_ENDIAN, can be selected on regarding get-method explicitly from user if needed
+ */
+public class DefaultModbusByteArrayFieldItem extends DefaultByteArrayFieldItem {
+
+    private static final int SHORT_BYTES = 2;
+    private static final int INTEGER_BYTES = 4;
+    private static final int LONG_BYTES = 8;
+    private static final ByteOrder DEFAULT_ENDIANNESS = ByteOrder.BIG_ENDIAN;
+
+    private ByteOrder byteOrder;
+
+    private Byte[] completeByteArray;
+
+    public DefaultModbusByteArrayFieldItem(Byte[]... values) {
+        super(values);
+        this.byteOrder = DEFAULT_ENDIANNESS;
+        this.completeByteArray = getCompleteByteArray();
+    }
+
+    @Override
+    public Object getObject(int index) {
+        return getValue(index);
+    }
+
+    @Override
+    public boolean isValidByteArray(int index) {
+        Byte[] value = getValue(index);
+        return value != null;
+    }
+
+    @Override
+    public Byte[] getByteArray(int index) {
+        return getValue(index);
+    }
+
+    @Override
+    public boolean isValidShort(int index) {
+        return  this.completeByteArray.length>=shortIndexToByteIndex(index)+SHORT_BYTES &&
+                validateByteValues(shortIndexToByteIndex(index),SHORT_BYTES);
+    }
+
+    @Override
+    public Short getShort(int index) {
+        if(isValidShort(index)){
+            return ByteBuffer
+                .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(shortIndexToByteIndex(index))))
+                .order(this.byteOrder)
+                .getShort();
+        }
+        return null;
+    }
+
+    /**
+     * returns the short result for the given index with explicit chose of ByteOrder
+     * @param index index in relation to the requested data-type (here Short), see comment of regarding index-transformation
+     * @param byteOrder byte-order used for decoding of byte-array
+     * @return resulting short value if valid data is given, null otherwise
+     */
+    public Short getShort(int index, ByteOrder byteOrder){
+        this.byteOrder = byteOrder;
+        return getShort(index);
+    }
+
+    /**
+     * converts the starting index of a short array to source type Byte
+     * e.g. user wants to request the 2nd long value --&gt; index=1 --&gt; byteIndex=2
+     * @param shortIndex index from users view
+     * @return resulting byteArrayIndex
+     */
+    private static int shortIndexToByteIndex(int shortIndex){
+        return shortIndex*SHORT_BYTES;
+    }
+
+    @Override
+    public boolean isValidInteger(int index) {
+        return  this.completeByteArray.length>=intIndexToByteIndex(index)+INTEGER_BYTES &&
+                validateByteValues(intIndexToByteIndex(index),INTEGER_BYTES);
+    }
+
+    @Override
+    public Integer getInteger(int index) {
+        if(isValidInteger(index)){
+            return ByteBuffer
+                .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(intIndexToByteIndex(index))))
+                .order(this.byteOrder)
+                .getInt();
+        }
+        return null;
+    }
+
+    /**
+     * returns the int result for the given index with explicit chose of ByteOrder
+     * @param index index in relation to the requested data-type (here Integer), see comment of regarding index-transformation
+     * @param byteOrder byte-order used for decoding of byte-array
+     * @return resulting short value if valid data is given, null otherwise
+     */
+    public Integer getInteger(int index, ByteOrder byteOrder){
+        this.byteOrder = byteOrder;
+        return getInteger(index);
+    }
+
+    /**
+     * converts the starting index of an int array to source type Byte
+     * e.g. user wants to request the 4th integer value --&gt; index=3 --&gt; byteIndex=12
+     * @param intIndex index from users view
+     * @return resulting byteArrayIndex
+     */
+    private static int intIndexToByteIndex(int intIndex){
+        return intIndex*INTEGER_BYTES;
+    }
+
+    @Override
+    public boolean isValidLong(int index) {
+        return  this.completeByteArray.length>=longIndexToByteIndex(index)+LONG_BYTES &&
+                validateByteValues(longIndexToByteIndex(index),LONG_BYTES);
+    }
+
+    @Override
+    public Long getLong(int index) {
+        if(isValidLong(index)){
+            return ByteBuffer
+                .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(longIndexToByteIndex(index))))
+                .order(this.byteOrder)
+                .getLong();
+        }
+        return null;
+    }
+
+    /**
+     * returns the long result for the given index with explicit chose of ByteOrder
+     * @param index index in relation to the requested data-type (here Long), see comment of regarding index-transformation
+     * @param byteOrder byte-order used for decoding of byte-array
+     * @return resulting short value if valid data is given, null otherwise
+     */
+    public Long getLong(int index,ByteOrder byteOrder) {
+        this.byteOrder = byteOrder;
+        return getLong(index);
+    }
+
+    /**
+     * converts the starting index of a long array to source type Byte
+     * e.g. user wants to request the 3rd long value --&gt; index=2 --&gt; byteIndex=16
+     * @param longIndex index from users view
+     * @return resulting byteArrayIndex
+     */
+    private static int longIndexToByteIndex(int longIndex){
+        return longIndex*LONG_BYTES;
+    }
+
+    /**
+     * validates if requested bytes contain only non-null values
+     * @param startIndex    index of the first byte requested
+     * @param length        amount of subsequent bytes
+     * @return  true if requested values are not-null, false otherwise
+     */
+    private boolean validateByteValues(int startIndex, int length){
+        for(int byteIndex=startIndex; byteIndex<startIndex+length;byteIndex++){
+            if(this.completeByteArray[byteIndex]==null){
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * derives an ordered byte array from the given values to simplify handling
+     * @return the ordered byte array
+     */
+    private Byte[] getCompleteByteArray(){
+        List<Byte> byteList = new ArrayList<>();
+        for(int valuesIndex=0;valuesIndex<getNumberOfValues();valuesIndex++){
+            byteList.addAll(Arrays.asList(getValue(valuesIndex)));
+        }
+        return byteList.toArray(new Byte[0]);
+    }
+
+    /**
+     * returns a subarray with the wanted index first
+     * @param index start-index of wanted value
+     * @return the sub-array
+     */
+    private Byte[] getByteArrayFromIndex(int index){
+        if(index>this.completeByteArray.length){
+            return new Byte[0];
+        }
+        return Arrays.copyOfRange(this.completeByteArray,index,this.completeByteArray.length);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        DefaultModbusByteArrayFieldItem that = (DefaultModbusByteArrayFieldItem) o;
+        return Arrays.equals(completeByteArray, that.completeByteArray);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + Arrays.hashCode(completeByteArray);
+        return result;
+    }
+
+    //ToDo: Implement conversion for Float and Unsigned-Datatypes
+
+    //ToDo: Add exceptions to avoid unwanted states --> e.g. neg indexes
+
+}
+
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java
index ce6be0d46..1bfb9d486 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java
@@ -39,8 +39,8 @@ Licensed to the Apache Software Foundation (ASF) under one
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.base.messages.*;
 import org.apache.plc4x.java.base.messages.items.DefaultBooleanFieldItem;
-import org.apache.plc4x.java.base.messages.items.DefaultByteArrayFieldItem;
 import org.apache.plc4x.java.base.messages.items.FieldItem;
+import org.apache.plc4x.java.modbus.messages.items.DefaultModbusByteArrayFieldItem;
 import org.apache.plc4x.java.modbus.model.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -281,7 +281,7 @@ protected void decode(ChannelHandlerContext ctx, ModbusTcpPayload msg, List<Obje
             LOGGER.debug("{}: Nothing", readHoldingRegistersResponse);
             ByteBuf byteBuf = readHoldingRegistersResponse.getRegisters();
             // TODO: use register method
-            DefaultByteArrayFieldItem data = produceRegisterValueList(byteBuf, field.getQuantity());
+            DefaultModbusByteArrayFieldItem data = produceRegisterValueList(byteBuf, field.getQuantity());
             Map<String, Pair<PlcResponseCode, FieldItem>> responseValues = new HashMap<>();
             responseValues.put(fieldName, new ImmutablePair<>(PlcResponseCode.OK, data));
             plcRequestContainer.getResponseFuture().complete(new DefaultPlcReadResponse((InternalPlcReadRequest) request, responseValues));
@@ -291,7 +291,7 @@ protected void decode(ChannelHandlerContext ctx, ModbusTcpPayload msg, List<Obje
             LOGGER.debug("{}: Nothing", readInputRegistersResponse);
             ByteBuf byteBuf = readInputRegistersResponse.getRegisters();
             // TODO: use register method
-            DefaultByteArrayFieldItem data = produceRegisterValueList(byteBuf, field.getQuantity());
+            DefaultModbusByteArrayFieldItem data = produceRegisterValueList(byteBuf, field.getQuantity());
             Map<String, Pair<PlcResponseCode, FieldItem>> responseValues = new HashMap<>();
             responseValues.put(fieldName, new ImmutablePair<>(PlcResponseCode.OK, data));
             plcRequestContainer.getResponseFuture().complete(new DefaultPlcReadResponse((InternalPlcReadRequest) request, responseValues));
@@ -510,7 +510,7 @@ private DefaultBooleanFieldItem produceCoilValueList(ByteBuf byteBuf, int expect
         return new DefaultBooleanFieldItem(data.toArray(new Boolean[0]));
     }
 
-    private DefaultByteArrayFieldItem produceRegisterValueList(ByteBuf byteBuf, int expectedQuantity) throws PlcProtocolException {
+    private DefaultModbusByteArrayFieldItem produceRegisterValueList(ByteBuf byteBuf, int expectedQuantity) throws PlcProtocolException {
         int readableBytes = byteBuf.readableBytes();
         if (readableBytes % 2 != 0) {
             throw new PlcProtocolException("Readables bytes should even: " + readableBytes);
@@ -521,6 +521,6 @@ private DefaultByteArrayFieldItem produceRegisterValueList(ByteBuf byteBuf, int
             byteBuf.readBytes(register);
             data.add(ArrayUtils.toObject(register));
         }
-        return new DefaultByteArrayFieldItem(data.toArray(new Byte[0][0]));
+        return new DefaultModbusByteArrayFieldItem(data.toArray(new Byte[0][0]));
     }
 }
diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java
index f3fb19d3f..4fa4e8038 100644
--- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java
+++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java
@@ -23,8 +23,8 @@ Licensed to the Apache Software Foundation (ASF) under one
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler;
 import org.apache.plc4x.java.base.messages.items.DefaultBooleanFieldItem;
-import org.apache.plc4x.java.base.messages.items.DefaultByteArrayFieldItem;
 import org.apache.plc4x.java.base.messages.items.FieldItem;
+import org.apache.plc4x.java.modbus.messages.items.DefaultModbusByteArrayFieldItem;
 import org.apache.plc4x.java.modbus.model.*;
 
 import java.util.BitSet;
@@ -109,6 +109,6 @@ public FieldItem encodeByteArray(PlcField field, Object[] values) {
                         " is not assignable to " + modbusField + " fields.");
             }
         }
-        return new DefaultByteArrayFieldItem(byteArrays.toArray(new Byte[0][0]));
+        return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0]));
     }
 }
diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItemTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItemTest.java
new file mode 100644
index 000000000..454afecad
--- /dev/null
+++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItemTest.java
@@ -0,0 +1,135 @@
+/*
+ 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.messages.items;
+
+import org.apache.plc4x.java.base.messages.items.FieldItem;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import static org.junit.Assert.*;
+
+@SuppressWarnings("unchecked")
+public class DefaultModbusByteArrayFieldItemTest {
+    @Test
+    public void convertByteArrayToIntegerTest() {
+        FieldItem fieldItem = getFieldItemForIntegerArray();
+
+        Integer itemInteger = fieldItem.getInteger(1);
+        assertEquals(456,itemInteger,0);
+    }
+
+    @Test
+    public void convertByteArrayToIntegerTestReturnsNull() {
+        FieldItem fieldItem = getFieldItemForIntegerArray();
+
+        Integer itemInteger = fieldItem.getInteger(17);
+        assertNull(itemInteger);
+    }
+
+    private static FieldItem getFieldItemForIntegerArray() {
+        int sizeIntByteBuffer = 12;
+        ByteBuffer byteBuffer = ByteBuffer.allocate(sizeIntByteBuffer);
+        byteBuffer.order(ByteOrder.BIG_ENDIAN);
+        byteBuffer.putInt(0,123);
+        byteBuffer.putInt(4,456);
+        byteBuffer.putInt(8,789);
+        Byte[][] byteArray = new Byte[sizeIntByteBuffer/2][2];
+        int cntByteBuffer=0;
+        for (byte b : byteBuffer.array()) {
+            int shortIndex=cntByteBuffer/2;
+            byteArray[shortIndex][cntByteBuffer%2] = b;
+            cntByteBuffer++;
+        }
+
+        return new DefaultModbusByteArrayFieldItem(byteArray);
+    }
+
+
+    @Test
+    public void convertByteArrayToShortTest() {
+        FieldItem fieldItem = getFieldItemForShortArray();
+
+        Short itemShort = fieldItem.getShort(3);
+        assertEquals(1011,itemShort,0);
+    }
+
+    @Test
+    public void convertByteArrayToShortTestReturnsNull() {
+        FieldItem fieldItem = getFieldItemForShortArray();
+
+        Short itemShort = fieldItem.getShort(7);
+        assertNull(itemShort);
+    }
+
+    private static FieldItem getFieldItemForShortArray() {
+        int sizeIntByteBuffer = 8;
+        ByteBuffer byteBuffer = ByteBuffer.allocate(sizeIntByteBuffer);
+        byteBuffer.order(ByteOrder.BIG_ENDIAN);
+        byteBuffer.putShort(0,(short)123);
+        byteBuffer.putShort(2,(short)456);
+        byteBuffer.putShort(4,(short)789);
+        byteBuffer.putShort(6,(short)1011);
+        Byte[][] byteArray = new Byte[sizeIntByteBuffer/2][2];
+        int cntByteBuffer=0;
+        for (byte b : byteBuffer.array()) {
+            int shortIndex=cntByteBuffer/2;
+            byteArray[shortIndex][cntByteBuffer%2] = b;
+            cntByteBuffer++;
+        }
+
+        return new DefaultModbusByteArrayFieldItem(byteArray);
+    }
+
+    @Test
+    public void convertByteArrayToLongTest() {
+        FieldItem fieldItem = getFieldItemForLongArray();
+
+        Long itemLong = fieldItem.getLong(1);
+        assertEquals(456789123L,itemLong,0);
+    }
+
+    @Test
+    public void convertByteArrayToLongTestReturnsNull() {
+        FieldItem fieldItem = getFieldItemForLongArray();
+
+        Long itemLong = fieldItem.getLong(4);
+        assertNull(itemLong);
+    }
+
+    private static FieldItem getFieldItemForLongArray() {
+        int sizeIntByteBuffer = 32;
+        ByteBuffer byteBuffer = ByteBuffer.allocate(sizeIntByteBuffer);
+        byteBuffer.order(ByteOrder.BIG_ENDIAN);
+        byteBuffer.putLong(0,123456789L);
+        byteBuffer.putLong(8,456789123L);
+        byteBuffer.putLong(16,789123456L);
+        byteBuffer.putLong(24,101110111011L);
+        Byte[][] byteArray = new Byte[sizeIntByteBuffer/2][2];
+        int cntByteBuffer=0;
+        for (byte b : byteBuffer.array()) {
+            int shortIndex=cntByteBuffer/2;
+            byteArray[shortIndex][cntByteBuffer%2] = b;
+            cntByteBuffer++;
+        }
+
+        return new DefaultModbusByteArrayFieldItem(byteArray);
+    }
+}
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services