diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/AbstractBinaryData.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/AbstractBinaryData.java new file mode 100644 index 00000000000..01bdb7c95ef --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/AbstractBinaryData.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2018 Eurotech and/or its affiliates and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eurotech + *******************************************************************************/ +package org.eclipse.kura.driver.binary; + +import static java.util.Objects.requireNonNull; + +public abstract class AbstractBinaryData implements BinaryData { + + protected final Endianness endianness; + protected final int size; + + /** + * Creates a new {@link BinaryData} instance. + * + * @param endianness + * the endianness of the data + * @param size + * the size of the data + */ + public AbstractBinaryData(Endianness endianness, int size) { + requireNonNull(endianness, "Endianness cannot be null"); + if (size <= 0) { + throw new IllegalArgumentException("Size must be positive"); + } + this.endianness = endianness; + this.size = size; + } + + /** + * @return the endianness of the data + */ + public Endianness getEndianness() { + return this.endianness; + } + + /** + * @return the size of the data + */ + public int getSize() { + return this.size; + } + +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java index df76df65f37..c02826616a1 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,49 +12,23 @@ package org.eclipse.kura.driver.binary; -import static java.util.Objects.requireNonNull; - /** * This class can be used to read/write a block of data in a {@link Buffer} to/from an instance of type T. * * @param * the type to be used for reading or writing. */ -public abstract class BinaryData { - - protected final Endianness endianness; - protected final int size; - - /** - * Creates a new {@link BinaryData} instance. - * - * @param endianness - * the endianness of the data - * @param size - * the size of the data - */ - public BinaryData(Endianness endianness, int size) { - requireNonNull(endianness, "Endianness cannot be null"); - if (size <= 0) { - throw new IllegalArgumentException("Size must be positive"); - } - this.endianness = endianness; - this.size = size; - } +public interface BinaryData { /** * @return the endianness of the data */ - public Endianness getEndianness() { - return this.endianness; - } + public Endianness getEndianness(); /** * @return the size of the data */ - public int getSize() { - return this.size; - } + public int getSize(); /** * Writes the provided value into the provided {@link Buffer} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArray.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArray.java new file mode 100644 index 00000000000..57dbba4287e --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArray.java @@ -0,0 +1,50 @@ +package org.eclipse.kura.driver.binary; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ByteArray extends AbstractBinaryData { + + private static final Logger logger = LoggerFactory.getLogger(ByteArray.class); + + public ByteArray(int size) { + super(Endianness.LITTLE_ENDIAN, size); + } + + @Override + public void write(Buffer buf, int offset, byte[] value) { + + final int transferSize = getTransferSize(buf, offset); + + buf.write(offset, transferSize, value); + } + + @Override + public byte[] read(final Buffer buf, final int offset) { + + final int transferSize = getTransferSize(buf, offset); + byte[] data = new byte[transferSize]; + + buf.read(offset, data); + + return data; + } + + private int getTransferSize(final Buffer buf, final int offset) { + + final int size = getSize(); + final int bufferAvailable = buf.getLength() - offset; + + if (bufferAvailable < size) { + logger.debug("received buffer is too small"); + } + + return Math.min(bufferAvailable, size); + } + + @Override + public Class getValueType() { + return byte[].class; + } + +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java index 26daea47c6b..c1c031c030f 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Double extends BinaryData { +class Double extends AbstractBinaryData { public Double(Endianness endianness) { super(endianness, 8); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java index 503d4ef77de..4ffc208173a 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Float extends BinaryData { +class Float extends AbstractBinaryData { public Float(Endianness endianness) { super(endianness, 4); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java index 7770acdd543..c3f13b522de 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Int16 extends BinaryData { +class Int16 extends AbstractBinaryData { public Int16(Endianness endianness) { super(endianness, 2); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java index 48daee00581..0c931acd7b9 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Int32 extends BinaryData { +class Int32 extends AbstractBinaryData { public Int32(Endianness endianness) { super(endianness, 4); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java index 95c92ced560..43e786ff334 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Int64 extends BinaryData { +class Int64 extends AbstractBinaryData { public Int64(Endianness endianness) { super(endianness, 8); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java index 5c81f3b300f..fdee3902110 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class Int8 extends BinaryData { +class Int8 extends AbstractBinaryData { public Int8() { super(Endianness.BIG_ENDIAN, 1); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/TypeUtil.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/TypeUtil.java new file mode 100644 index 00000000000..e245e640bcb --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/TypeUtil.java @@ -0,0 +1,108 @@ +package org.eclipse.kura.driver.binary; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.function.Function; + +import org.eclipse.kura.type.BooleanValue; +import org.eclipse.kura.type.DataType; +import org.eclipse.kura.type.DoubleValue; +import org.eclipse.kura.type.FloatValue; +import org.eclipse.kura.type.IntegerValue; +import org.eclipse.kura.type.LongValue; +import org.eclipse.kura.type.StringValue; +import org.eclipse.kura.type.TypedValue; + +public final class TypeUtil { + + private TypeUtil() { + } + + public static Function> toTypedValue(final Class sourceType, final DataType targetType) { + if (targetType == DataType.STRING) { + if (sourceType == byte[].class) { + return value -> new StringValue(Arrays.toString((byte[]) value)); + } else { + return value -> new StringValue(value.toString()); + } + } + if (targetType == DataType.BOOLEAN) { + if (sourceType == Boolean.class) { + return value -> new BooleanValue((Boolean) value); + } else if (sourceType == String.class) { + return value -> new BooleanValue(Boolean.parseBoolean((String) value)); + } else if (sourceType.isAssignableFrom(Number.class)) { + return value -> new BooleanValue(((Number) value).doubleValue() != 0); + } + } + if (Number.class.isAssignableFrom(sourceType)) { + if (targetType == DataType.INTEGER) { + return value -> new IntegerValue(((Number) value).intValue()); + } else if (targetType == DataType.LONG) { + return value -> new LongValue(((Number) value).longValue()); + } else if (targetType == DataType.FLOAT) { + return value -> new FloatValue(((Number) value).floatValue()); + } else if (targetType == DataType.DOUBLE) { + return value -> new DoubleValue(((Number) value).doubleValue()); + } + } + if (sourceType == String.class) { + if (targetType == DataType.INTEGER) { + return value -> new IntegerValue(Integer.parseInt((String) value)); + } else if (targetType == DataType.LONG) { + return value -> new LongValue(Long.parseLong((String) value)); + } else if (targetType == DataType.FLOAT) { + return value -> new FloatValue(java.lang.Float.parseFloat((String) value)); + } else if (targetType == DataType.DOUBLE) { + return value -> new DoubleValue(java.lang.Double.parseDouble((String) value)); + } + } + throw new IllegalArgumentException("Cannot convert from native type " + sourceType.getSimpleName() + + " to Kura data type " + targetType.name()); + } + + @SuppressWarnings("unchecked") + public static Function, T> fromTypedValue(final Class targetType, final DataType sourceType) { + if (targetType == String.class) { + if (sourceType == DataType.BYTE_ARRAY) { + return value -> (T) Arrays.toString((byte[]) value.getValue()); + } else { + return value -> (T) value.toString(); + } + } + if (targetType == Boolean.class) { + if (sourceType == DataType.BOOLEAN) { + return value -> (T) value.getValue(); + } else if (sourceType == DataType.STRING) { + return value -> (T) (Boolean) Boolean.parseBoolean((String) value.getValue()); + } else if (sourceType != DataType.BYTE_ARRAY) { + return value -> (T) (Boolean) (((Number) value.getValue()).doubleValue() != 0); + } + } + if (sourceType == DataType.STRING) { + if (targetType == Integer.class) { + return value -> (T) (Integer) Integer.parseInt((String) value.getValue()); + } else if (targetType == Long.class) { + return value -> (T) (Long) Long.parseLong((String) value.getValue()); + } else if (targetType == java.lang.Float.class) { + return value -> (T) (java.lang.Float) java.lang.Float.parseFloat((String) value.getValue()); + } else if (targetType == java.lang.Double.class) { + return value -> (T) (java.lang.Double) java.lang.Double.parseDouble((String) value.getValue()); + } + } else { + if (targetType == Integer.class) { + return value -> (T) (Integer) ((Number) value.getValue()).intValue(); + } else if (targetType == Long.class) { + return value -> (T) (Long) ((Number) value.getValue()).longValue(); + } else if (targetType == java.lang.Float.class) { + return value -> (T) (java.lang.Float) ((Number) value.getValue()).floatValue(); + } else if (targetType == java.lang.Double.class) { + return value -> (T) (java.lang.Double) ((Number) value.getValue()).doubleValue(); + } else if (targetType == BigInteger.class) { + return value -> (T) BigInteger.valueOf(((Number) value.getValue()).longValue()); + } + } + throw new IllegalArgumentException("Cannot convert from Kura data type " + sourceType.name() + + " to native type " + targetType.getSimpleName()); + } +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java index cf4df8a7e7b..34055df37a1 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class UInt16 extends BinaryData { +class UInt16 extends AbstractBinaryData { public UInt16(Endianness endianness) { super(endianness, 2); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java index 9d854c8ec1f..88e82d7337e 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class UInt32 extends BinaryData { +class UInt32 extends AbstractBinaryData { public UInt32(Endianness endianness) { super(endianness, 4); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java index 0d88cc58ba1..6f4fc92d856 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,7 +12,7 @@ package org.eclipse.kura.driver.binary; -class UInt8 extends BinaryData { +class UInt8 extends AbstractBinaryData { public UInt8() { super(Endianness.BIG_ENDIAN, 1); diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UnsignedIntegerLE.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UnsignedIntegerLE.java new file mode 100644 index 00000000000..1fb7ceb9751 --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UnsignedIntegerLE.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2018 Eurotech and/or its affiliates and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eurotech + *******************************************************************************/ +package org.eclipse.kura.driver.binary; + +import java.math.BigInteger; + +public class UnsignedIntegerLE extends AbstractBinaryData { + + private final int startBitOffset; + private final int sizeBits; + + public UnsignedIntegerLE(final int sizeBits, final int startBitOffset) { + super(Endianness.LITTLE_ENDIAN, getSizeBytes(sizeBits)); + this.startBitOffset = startBitOffset; + this.sizeBits = sizeBits; + } + + @Override + public void write(Buffer buf, int offset, BigInteger value) { + throw new UnsupportedOperationException(); + } + + @Override + public BigInteger read(final Buffer buf, final int offset) { + final int sizeBytes = getSize(); + + final byte[] raw = new byte[sizeBytes]; + + int srcBit = offset * 8 + startBitOffset; + final int srcEnd = srcBit + sizeBits; + + int dstBit = 0; + + while (srcBit < srcEnd) { + final int srcByte = srcBit / 8; + final int dstByte = dstBit / 8; + + if ((buf.get(srcByte) & 0xff & (1 << (srcBit % 8))) != 0) { + raw[dstByte] |= (1 << (dstBit % 8)); + } + + srcBit++; + dstBit++; + } + + for (int i = 0; i < sizeBytes / 2; i++) { + final byte tmp = raw[i]; + raw[i] = raw[sizeBytes - i - 1]; + raw[sizeBytes - i - 1] = tmp; + } + + return new BigInteger(1, raw); + } + + @Override + public Class getValueType() { + return BigInteger.class; + } + + private static int getSizeBytes(final int sizeBits) { + if (sizeBits <= 0) { + throw new IllegalArgumentException("bit size must be positive"); + } + return (int) Math.ceil((double) sizeBits / 8); + } +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/GainOffset.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/GainOffset.java new file mode 100644 index 00000000000..ca1aca840bc --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/GainOffset.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2018 Eurotech and/or its affiliates and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eurotech + *******************************************************************************/ +package org.eclipse.kura.driver.binary.adapter; + +import java.math.BigInteger; +import java.util.function.Function; + +import org.eclipse.kura.driver.binary.BinaryData; +import org.eclipse.kura.driver.binary.Buffer; +import org.eclipse.kura.driver.binary.Endianness; + +public class GainOffset implements BinaryData { + + private final BinaryData wrapped; + private final double gain; + private final double off; + + private Function fromDouble; + + public GainOffset(final BinaryData wrapped, final double gain, final double offset) { + this.wrapped = wrapped; + this.gain = gain; + this.off = offset; + this.fromDouble = fromDouble(wrapped.getValueType()); + } + + @Override + public void write(Buffer buf, int offset, T value) { + final double d = value.doubleValue() * gain + off; + wrapped.write(buf, offset, this.fromDouble.apply(d)); + } + + @Override + public T read(Buffer buf, int offset) { + final T value = wrapped.read(buf, offset); + return fromDouble.apply(value.doubleValue() * gain + off); + } + + @Override + public Class getValueType() { + return wrapped.getValueType(); + } + + @SuppressWarnings("unchecked") + private static Function fromDouble(final Class targetType) { + if (targetType == Byte.class) { + return value -> (T) (Byte) value.byteValue(); + } else if (targetType == Short.class) { + return value -> (T) (Short) value.shortValue(); + } else if (targetType == Integer.class) { + return value -> (T) (Integer) value.intValue(); + } else if (targetType == Long.class) { + return value -> (T) (Long) value.longValue(); + } else if (targetType == java.lang.Float.class) { + return value -> (T) (Float) value.floatValue(); + } else if (targetType == java.lang.Double.class) { + return value -> (T) (Double) value.doubleValue(); + } else if (targetType == BigInteger.class) { + return value -> (T) BigInteger.valueOf(value.longValue()); + } + + throw new IllegalArgumentException("cannot convert from double to " + targetType.getSimpleName()); + } + + @Override + public Endianness getEndianness() { + return wrapped.getEndianness(); + } + + @Override + public int getSize() { + return wrapped.getSize(); + } + +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/StringData.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/StringData.java new file mode 100644 index 00000000000..3dd49e884df --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/StringData.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eurotech + *******************************************************************************/ +package org.eclipse.kura.driver.binary.adapter; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.eclipse.kura.driver.binary.BinaryData; +import org.eclipse.kura.driver.binary.Buffer; +import org.eclipse.kura.driver.binary.Endianness; + +public class StringData implements BinaryData { + + private final BinaryData wrapped; + private final Charset charset; + + public StringData(final BinaryData wrapped, final Charset charset) { + this.wrapped = wrapped; + this.charset = charset; + } + + @Override + public Endianness getEndianness() { + return wrapped.getEndianness(); + } + + @Override + public int getSize() { + return wrapped.getSize(); + } + + @Override + public void write(Buffer buf, int offset, String value) { + final byte[] raw = value.getBytes(charset); + wrapped.write(buf, offset, raw); + } + + @Override + public String read(Buffer buf, int offset) { + final byte[] raw = wrapped.read(buf, offset); + return new String(raw, StandardCharsets.US_ASCII); + } + + @Override + public Class getValueType() { + return String.class; + } + +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/ToBoolean.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/ToBoolean.java new file mode 100644 index 00000000000..e4faa881fa3 --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/ToBoolean.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2018 Eurotech and/or its affiliates and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eurotech + *******************************************************************************/ +package org.eclipse.kura.driver.binary.adapter; + +import org.eclipse.kura.driver.binary.BinaryData; +import org.eclipse.kura.driver.binary.Buffer; +import org.eclipse.kura.driver.binary.Endianness; + +public class ToBoolean implements BinaryData { + + final BinaryData wrapped; + + public ToBoolean(final BinaryData wrapped) { + this.wrapped = wrapped; + } + + @Override + public void write(final Buffer buf, final int offset, final Boolean value) { + throw new UnsupportedOperationException(); + } + + @Override + public Boolean read(final Buffer buf, int offset) { + return ((Number) wrapped.read(buf, offset)).doubleValue() != 0; + } + + @Override + public Class getValueType() { + return Boolean.class; + } + + @Override + public Endianness getEndianness() { + return wrapped.getEndianness(); + } + + @Override + public int getSize() { + return wrapped.getSize(); + } + +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java index dde37339669..c63787571fb 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -13,19 +13,13 @@ package org.eclipse.kura.driver.block.task; import java.io.IOException; -import java.util.Arrays; import java.util.function.Function; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.Buffer; -import org.eclipse.kura.type.BooleanValue; +import org.eclipse.kura.driver.binary.TypeUtil; import org.eclipse.kura.type.DataType; -import org.eclipse.kura.type.DoubleValue; -import org.eclipse.kura.type.FloatValue; -import org.eclipse.kura.type.IntegerValue; -import org.eclipse.kura.type.LongValue; -import org.eclipse.kura.type.StringValue; import org.eclipse.kura.type.TypedValue; import org.eclipse.kura.type.TypedValues; import org.slf4j.Logger; @@ -42,14 +36,13 @@ public class BinaryDataTask extends ChannelBlockTask { @SuppressWarnings("unchecked") public BinaryDataTask(ChannelRecord record, int offset, BinaryData dataType, Mode mode) { - this(record, offset, dataType, value -> TypedValues.newTypedValue(value), - typedValue -> (T) typedValue.getValue(), mode); + this(record, offset, dataType, TypedValues::newTypedValue, typedValue -> (T) typedValue.getValue(), mode); } public BinaryDataTask(ChannelRecord record, int offset, BinaryData binaryDataType, DataType dataType, Mode mode) { - this(record, offset, binaryDataType, createToTypedValueAdapter(binaryDataType.getValueType(), dataType), - createFromTypedValueAdapter(binaryDataType.getValueType(), dataType), mode); + this(record, offset, binaryDataType, TypeUtil.toTypedValue(binaryDataType.getValueType(), dataType), + TypeUtil.fromTypedValue(binaryDataType.getValueType(), dataType), mode); } public BinaryDataTask(ChannelRecord record, int offset, BinaryData dataType, @@ -81,86 +74,4 @@ public void run() throws IOException { } } - private static Function> createToTypedValueAdapter(Class sourceType, DataType targetType) { - if (targetType == DataType.STRING) { - if (sourceType == byte[].class) { - return value -> new StringValue(Arrays.toString((byte[]) value)); - } else { - return value -> new StringValue(value.toString()); - } - } - if (targetType == DataType.BOOLEAN) { - if (sourceType == Boolean.class) { - return value -> new BooleanValue((Boolean) value); - } else if (sourceType == String.class) { - return value -> new BooleanValue(Boolean.parseBoolean((String) value)); - } - } - if (Number.class.isAssignableFrom(sourceType)) { - if (targetType == DataType.INTEGER) { - return value -> new IntegerValue(((Number) value).intValue()); - } else if (targetType == DataType.LONG) { - return value -> new LongValue(((Number) value).longValue()); - } else if (targetType == DataType.FLOAT) { - return value -> new FloatValue(((Number) value).floatValue()); - } else if (targetType == DataType.DOUBLE) { - return value -> new DoubleValue(((Number) value).doubleValue()); - } - } - if (sourceType == String.class) { - if (targetType == DataType.INTEGER) { - return value -> new IntegerValue(Integer.parseInt((String) value)); - } else if (targetType == DataType.LONG) { - return value -> new LongValue(Long.parseLong((String) value)); - } else if (targetType == DataType.FLOAT) { - return value -> new FloatValue(Float.parseFloat((String) value)); - } else if (targetType == DataType.DOUBLE) { - return value -> new DoubleValue(Double.parseDouble((String) value)); - } - } - throw new IllegalArgumentException("Cannot convert from native type " + sourceType.getSimpleName() - + " to Kura data type " + targetType.name()); - } - - @SuppressWarnings("unchecked") - private static Function, T> createFromTypedValueAdapter(Class targetType, - DataType sourceType) { - if (targetType == String.class) { - if (sourceType == DataType.BYTE_ARRAY) { - return value -> (T) Arrays.toString((byte[]) value.getValue()); - } else { - return value -> (T) value.toString(); - } - } - if (targetType == Boolean.class) { - if (sourceType == DataType.BOOLEAN) { - return value -> (T) value.getValue(); - } else if (sourceType == DataType.STRING) { - return value -> (T) (Boolean) Boolean.parseBoolean((String) value.getValue()); - } - } - if (sourceType == DataType.STRING) { - if (targetType == Integer.class) { - return value -> (T) (Integer) Integer.parseInt((String) value.getValue()); - } else if (targetType == Long.class) { - return value -> (T) (Long) Long.parseLong((String) value.getValue()); - } else if (targetType == Float.class) { - return value -> (T) (Float) Float.parseFloat((String) value.getValue()); - } else if (targetType == Double.class) { - return value -> (T) (Double) Double.parseDouble((String) value.getValue()); - } - } else { - if (targetType == Integer.class) { - return value -> (T) (Integer) ((Number) value.getValue()).intValue(); - } else if (targetType == Long.class) { - return value -> (T) (Long) ((Number) value.getValue()).longValue(); - } else if (targetType == Float.class) { - return value -> (T) (Float) ((Number) value.getValue()).floatValue(); - } else if (targetType == Double.class) { - return value -> (T) (Double) ((Number) value.getValue()).doubleValue(); - } - } - throw new IllegalArgumentException("Cannot convert from Kura data type " + sourceType.name() - + " to native type " + targetType.getSimpleName()); - } } diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java index 528e27f6961..d12b832ea76 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -13,39 +13,11 @@ package org.eclipse.kura.driver.block.task; import org.eclipse.kura.channel.ChannelRecord; -import org.eclipse.kura.driver.binary.Buffer; -import org.eclipse.kura.type.ByteArrayValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.kura.driver.binary.ByteArray; -public class ByteArrayTask extends ChannelBlockTask { - - private static final Logger logger = LoggerFactory.getLogger(ByteArrayTask.class); +public class ByteArrayTask extends BinaryDataTask { public ByteArrayTask(ChannelRecord record, int start, int end, Mode mode) { - super(record, start, end, mode); - } - - @Override - public void run() { - final ToplevelBlockTask parent = getParent(); - Buffer buffer = parent.getBuffer(); - - if (getMode() == Mode.READ) { - byte[] data = new byte[getEnd() - getStart()]; - logger.debug("Read byte array: offset: {} length: {}", getStart(), data.length); - - buffer.read(getStart() - parent.getStart(), data); - - this.record.setValue(new ByteArrayValue(data)); - onSuccess(); - } else { - byte[] value = (byte[]) this.record.getValue().getValue(); - int writeLength = Math.min(getEnd() - getStart(), value.length); - - logger.debug("Write byte array: offset: {} length: {}", getStart(), writeLength); - - buffer.write(getStart() - parent.getStart(), writeLength, value); - } + super(record, start, new ByteArray(end - start), mode); } } diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java index cd39bf3f625..f5996423502 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -46,6 +46,10 @@ public ChannelBlockTask(ChannelRecord record, int start, int end, Mode mode) { this.record = record; } + public ChannelRecord getRecord() { + return record; + } + /** * Sets the {@link ChannelStatus} of the associated {@link ChannelRecord} to report a success state * and updates the timestamp. diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTaskWrapper.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTaskWrapper.java new file mode 100644 index 00000000000..20c5d3a07c0 --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTaskWrapper.java @@ -0,0 +1,53 @@ +package org.eclipse.kura.driver.block.task; + +public abstract class ChannelBlockTaskWrapper extends ChannelBlockTask { + + private final ChannelBlockTask wrapped; + + public ChannelBlockTaskWrapper(final ChannelBlockTask wrapped) { + super(wrapped.getRecord(), wrapped.getStart(), wrapped.getEnd(), wrapped.getMode()); + this.wrapped = wrapped; + } + + public ChannelBlockTask getWrappedTask() { + return wrapped; + } + + @Override + public void setParent(final ToplevelBlockTask parent) { + super.setParent(parent); + wrapped.setParent(parent); + } + + @Override + public int getStart() { + return wrapped.getStart(); + } + + @Override + public int getEnd() { + return wrapped.getEnd(); + } + + @Override + public void setEnd(int end) { + super.setEnd(end); + wrapped.setEnd(end); + } + + @Override + public void setStart(int start) { + super.setStart(start); + wrapped.setStart(start); + } + + @Override + public void onSuccess() { + wrapped.onSuccess(); + } + + @Override + public void onFailure(final Exception exception) { + wrapped.onFailure(exception); + } +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelListenerBlockTask.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelListenerBlockTask.java new file mode 100644 index 00000000000..1fcca1b1a17 --- /dev/null +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelListenerBlockTask.java @@ -0,0 +1,30 @@ +package org.eclipse.kura.driver.block.task; + +import java.io.IOException; + +import org.eclipse.kura.channel.listener.ChannelEvent; +import org.eclipse.kura.channel.listener.ChannelListener; + +public class ChannelListenerBlockTask extends ChannelBlockTaskWrapper { + + private final ChannelListener listener; + + public ChannelListenerBlockTask(final ChannelBlockTask wrapped, final ChannelListener listener) { + super(wrapped); + + this.listener = listener; + } + + public ChannelListener getListener() { + return listener; + } + + @Override + public void run() throws IOException { + final ChannelBlockTask wrapped = getWrappedTask(); + + wrapped.run(); + + listener.onChannelEvent(new ChannelEvent(wrapped.getRecord())); + } +} diff --git a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java index 9cd80c409df..21364877eaf 100644 --- a/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java +++ b/kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Eurotech and/or its affiliates and others + * Copyright (c) 2017, 2018 Eurotech and/or its affiliates and others * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -15,43 +15,12 @@ import java.nio.charset.StandardCharsets; import org.eclipse.kura.channel.ChannelRecord; -import org.eclipse.kura.driver.binary.Buffer; -import org.eclipse.kura.type.StringValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.kura.driver.binary.ByteArray; +import org.eclipse.kura.driver.binary.adapter.StringData; -public class StringTask extends ChannelBlockTask { - - private static final Logger logger = LoggerFactory.getLogger(StringTask.class); +public class StringTask extends BinaryDataTask { public StringTask(ChannelRecord record, int start, int end, Mode mode) { - super(record, start, end, mode); - } - - @Override - public void run() { - final ToplevelBlockTask parent = getParent(); - final Buffer buffer = parent.getBuffer(); - - if (getMode() == Mode.READ) { - byte[] data = new byte[getEnd() - getStart()]; - buffer.read(getStart() - parent.getStart(), data); - - final String result = new String(data, StandardCharsets.US_ASCII); - - logger.debug("Read string: offset: {} length: {} result: {}", getStart(), data.length, result); - - this.record.setValue(new StringValue(result)); - onSuccess(); - } else { - String value = (String) this.record.getValue().getValue(); - int writeLength = Math.min(getEnd() - getStart(), value.length()); - - logger.debug("Write string: offset: {} length: {} value: {}", getStart(), writeLength, value); - - final byte[] data = value.getBytes(StandardCharsets.US_ASCII); - - buffer.write(getStart() - parent.getStart(), data); - } + super(record, start, new StringData(new ByteArray(end - start), StandardCharsets.US_ASCII), mode); } } \ No newline at end of file diff --git a/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BinaryDataTest.java b/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BinaryDataTest.java index 5471662b9f5..baee67831dc 100644 --- a/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BinaryDataTest.java +++ b/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BinaryDataTest.java @@ -15,13 +15,24 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Function; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.BinaryDataTypes; +import org.eclipse.kura.driver.binary.Buffer; +import org.eclipse.kura.driver.binary.ByteArray; import org.eclipse.kura.driver.binary.ByteArrayBuffer; import org.eclipse.kura.driver.binary.Endianness; +import org.eclipse.kura.driver.binary.UnsignedIntegerLE; +import org.eclipse.kura.driver.binary.adapter.GainOffset; +import org.eclipse.kura.driver.binary.adapter.StringData; +import org.eclipse.kura.driver.binary.adapter.ToBoolean; +import org.junit.Assert; import org.junit.Test; public class BinaryDataTest { @@ -151,6 +162,116 @@ public void shouldSupportDoublePositiveMin() { testReadWrite(BinaryDataTypes.DOUBLE_LE, BinaryDataTest::createFloatPositiveMin, Double.MIN_VALUE); } + @Test + public void shouldSupportUnsignedInteger() { + final byte[] testBuf = new byte[] { 1, 2, 3, 4 }; + testRead(new UnsignedIntegerLE(32, 0), (endiannes, size) -> testBuf, BigInteger.valueOf(67305985)); + + final byte[] testBuf2 = new byte[] { (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA }; + testRead(new UnsignedIntegerLE(3, 0), (endiannes, size) -> testBuf2, BigInteger.valueOf(2)); + testRead(new UnsignedIntegerLE(3, 3), (endiannes, size) -> testBuf2, BigInteger.valueOf(5)); + testRead(new UnsignedIntegerLE(6, 2), (endiannes, size) -> testBuf2, BigInteger.valueOf(42)); + testRead(new UnsignedIntegerLE(2, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(1)); + testRead(new UnsignedIntegerLE(12, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(1365)); + testRead(new UnsignedIntegerLE(17, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(87381)); + } + + @Test + public void shouldSupportByteArray() { + final byte[] testBuf = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + testRead(new ByteArray(testBuf.length), (size, endianness) -> testBuf, testBuf, Assert::assertArrayEquals); + testRead(new ByteArray(4), (size, endianness) -> testBuf, new byte[] { 1, 2, 3, 4 }, Assert::assertArrayEquals); + testRead(new ByteArray(40), (size, endianness) -> testBuf, testBuf, Assert::assertArrayEquals); + } + + @Test + public void shouldSupportGainOffset() { + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (byte) 10, (byte) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (short) 10, (short) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (int) 10, (int) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (long) 10, (long) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (short) 10, (short) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (float) 10, (float) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), (double) 10, (double) 10); + testAdapterRead(a -> new GainOffset<>(a, 1.0f, 0.0f), BigInteger.valueOf(10), BigInteger.valueOf(10)); + + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (byte) 10, (byte) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (short) 10, (short) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (int) 10, (int) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (long) 10, (long) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (short) 10, (short) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (float) 10, (float) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), (double) 10, (double) 10); + testAdapterWrite(a -> new GainOffset<>(a, 1.0f, 0.0f), BigInteger.valueOf(10), BigInteger.valueOf(10)); + + testAdapterRead(a -> new GainOffset<>(a, 2.0f, 0.0f), (byte) 10, (byte) 20); + testAdapterRead(a -> new GainOffset<>(a, 3.0f, 0.0f), (short) 10, (short) 30); + testAdapterRead(a -> new GainOffset<>(a, 5.0f, 0.0f), (int) 10, (int) 50); + testAdapterRead(a -> new GainOffset<>(a, 15.0f, 0.0f), (long) 10, (long) 150); + testAdapterRead(a -> new GainOffset<>(a, -1.0f, 0.0f), (short) 10, (short) -10); + testAdapterRead(a -> new GainOffset<>(a, -2.0f, 0.0f), (float) 10, (float) -20); + testAdapterRead(a -> new GainOffset<>(a, -5.0f, 0.0f), (double) 10, (double) -50); + testAdapterRead(a -> new GainOffset<>(a, -11.0f, 0.0f), BigInteger.valueOf(10), BigInteger.valueOf(-110)); + + testAdapterRead(a -> new GainOffset<>(a, 2.0f, 1.0f), (byte) 10, (byte) (20 + 1)); + testAdapterRead(a -> new GainOffset<>(a, 3.0f, 4.0f), (short) 10, (short) (30 + 4)); + testAdapterRead(a -> new GainOffset<>(a, 5.0f, -2.0f), (int) 10, (int) (50 - 2)); + testAdapterRead(a -> new GainOffset<>(a, 15.0f, -5.0f), (long) 10, (long) (150 - 5)); + testAdapterRead(a -> new GainOffset<>(a, -1.0f, 10.0f), (short) 10, (short) (-10 + 10)); + testAdapterRead(a -> new GainOffset<>(a, -2.0f, 54.0f), (float) 10, (float) (-20 + 54)); + testAdapterRead(a -> new GainOffset<>(a, -5.0f, 1.0f), (double) 10, (double) (-50 + 1)); + testAdapterRead(a -> new GainOffset<>(a, -11.0f, 22.0f), BigInteger.valueOf(10), BigInteger.valueOf(-110 + 22)); + + testAdapterWrite(a -> new GainOffset<>(a, 2.0f, 0.0f), (byte) 10, (byte) 20); + testAdapterWrite(a -> new GainOffset<>(a, 3.0f, 0.0f), (short) 10, (short) 30); + testAdapterWrite(a -> new GainOffset<>(a, 5.0f, 0.0f), (int) 10, (int) 50); + testAdapterWrite(a -> new GainOffset<>(a, 15.0f, 0.0f), (long) 10, (long) 150); + testAdapterWrite(a -> new GainOffset<>(a, -1.0f, 0.0f), (short) 10, (short) -10); + testAdapterWrite(a -> new GainOffset<>(a, -2.0f, 0.0f), (float) 10, (float) -20); + testAdapterWrite(a -> new GainOffset<>(a, -5.0f, 0.0f), (double) 10, (double) -50); + testAdapterWrite(a -> new GainOffset<>(a, -11.0f, 0.0f), BigInteger.valueOf(10), BigInteger.valueOf(-110)); + + testAdapterWrite(a -> new GainOffset<>(a, 2.0f, 1.0f), (byte) 10, (byte) (20 + 1)); + testAdapterWrite(a -> new GainOffset<>(a, 3.0f, 4.0f), (short) 10, (short) (30 + 4)); + testAdapterWrite(a -> new GainOffset<>(a, 5.0f, -2.0f), (int) 10, (int) (50 - 2)); + testAdapterWrite(a -> new GainOffset<>(a, 15.0f, -5.0f), (long) 10, (long) (150 - 5)); + testAdapterWrite(a -> new GainOffset<>(a, -1.0f, 10.0f), (short) 10, (short) (-10 + 10)); + testAdapterWrite(a -> new GainOffset<>(a, -2.0f, 54.0f), (float) 10, (float) (-20 + 54)); + testAdapterWrite(a -> new GainOffset<>(a, -5.0f, 1.0f), (double) 10, (double) (-50 + 1)); + testAdapterWrite(a -> new GainOffset<>(a, -11.0f, 22.0f), BigInteger.valueOf(10), + BigInteger.valueOf(-110 + 22)); + } + + @Test + public void shouldSupportStringData() { + testAdapterRead(a -> new StringData(a, StandardCharsets.US_ASCII), new byte[] { 0x74, 0x65, 0x73, 0x74 }, + "test"); + testAdapterWrite(a -> new StringData(a, StandardCharsets.US_ASCII), "test", + new byte[] { 0x74, 0x65, 0x73, 0x74 }, Assert::assertArrayEquals); + } + + @Test + public void shouldSupportToBooolean() { + testAdapterRead(ToBoolean::new, (byte) 10, true); + testAdapterRead(ToBoolean::new, (short) 10, true); + testAdapterRead(ToBoolean::new, (int) 10, true); + testAdapterRead(ToBoolean::new, (long) 10, true); + testAdapterRead(ToBoolean::new, (short) 10, true); + testAdapterRead(ToBoolean::new, (float) 10, true); + testAdapterRead(ToBoolean::new, (double) 10, true); + testAdapterRead(ToBoolean::new, BigInteger.valueOf(10), true); + + testAdapterRead(ToBoolean::new, (byte) 0, false); + testAdapterRead(ToBoolean::new, (short) 0, false); + testAdapterRead(ToBoolean::new, (int) 0, false); + testAdapterRead(ToBoolean::new, (long) 0, false); + testAdapterRead(ToBoolean::new, (short) 0, false); + testAdapterRead(ToBoolean::new, (float) 0, false); + testAdapterRead(ToBoolean::new, (double) 0, false); + testAdapterRead(ToBoolean::new, BigInteger.valueOf(0), false); + } + private static void apply(byte[] data, Endianness endianness, BiFunction func) { int start; int inc; @@ -234,13 +355,115 @@ private static byte[] createDoubleMax(Endianness endianness, int size) { return result; } + private void testRead(BinaryData data, BiFunction bufferProvider, + T expectedValue) { + testRead(data, bufferProvider, expectedValue, Assert::assertEquals); + } + + private void testRead(BinaryData data, BiFunction bufferProvider, + T expectedValue, final BiConsumer validator) { + ByteArrayBuffer testBuf = new ByteArrayBuffer(bufferProvider.apply(data.getEndianness(), data.getSize())); + validator.accept(expectedValue, data.read(testBuf, 0)); + } + private void testReadWrite(BinaryData data, BiFunction bufferProvider, T expectedValue) { + testReadWrite(data, bufferProvider, expectedValue, Assert::assertEquals); + } + + private void testReadWrite(BinaryData data, BiFunction bufferProvider, + T expectedValue, final BiConsumer readValidator) { ByteArrayBuffer testBuf = new ByteArrayBuffer(bufferProvider.apply(data.getEndianness(), data.getSize())); - assertEquals(expectedValue, data.read(testBuf, 0)); + readValidator.accept(expectedValue, data.read(testBuf, 0)); ByteArrayBuffer writeBuf = new ByteArrayBuffer(new byte[data.getSize()]); data.write(writeBuf, 0, expectedValue); assertArrayEquals(testBuf.getBackingArray(), writeBuf.getBackingArray()); } + private void testAdapterRead(final Function, BinaryData> supplier, final T suppliedValue, + final U expectedValue) { + testAdapterRead(supplier, suppliedValue, expectedValue, Assert::assertEquals); + } + + private void testAdapterWrite(final Function, BinaryData> supplier, final U writtenValue, + final T forwardedValue) { + testAdapterWrite(supplier, writtenValue, forwardedValue, Assert::assertEquals); + } + + private void testAdapterRead(final Function, BinaryData> supplier, final T suppliedValue, + final U expectedValue, final BiConsumer validator) { + final AdapterHelper helper = new AdapterHelper<>(suppliedValue); + final BinaryData underTest = supplier.apply(helper); + helper.assertIsWrapper(underTest); + validator.accept(expectedValue, underTest.read(new ByteArrayBuffer(new byte[0]), 0)); + } + + private void testAdapterWrite(final Function, BinaryData> supplier, final U writtenValue, + final T forwardedValue, final BiConsumer validator) { + @SuppressWarnings("unchecked") + final AdapterHelper helper = new AdapterHelper<>((Class) forwardedValue.getClass()); + final BinaryData underTest = supplier.apply(helper); + helper.assertIsWrapper(underTest); + underTest.write(new ByteArrayBuffer(new byte[0]), 0, writtenValue); + validator.accept(forwardedValue, helper.getValue()); + } + + private static final class AdapterHelper implements BinaryData { + + private T value; + private final Class valueType; + private final Endianness endianness; + private final int size; + + public AdapterHelper(T value, Class valueType, Endianness endianness, int size) { + this.value = value; + this.valueType = valueType; + this.endianness = endianness; + this.size = size; + } + + @SuppressWarnings("unchecked") + public AdapterHelper(final T value) { + this(value, (Class) value.getClass(), Endianness.LITTLE_ENDIAN, 1); + } + + public AdapterHelper(final Class valueType) { + this(null, valueType, Endianness.LITTLE_ENDIAN, 1); + } + + @Override + public Endianness getEndianness() { + return endianness; + } + + @Override + public int getSize() { + return size; + } + + @Override + public void write(Buffer buf, int offset, T value) { + this.value = value; + } + + @Override + public T read(Buffer buf, int offset) { + return value; + } + + public T getValue() { + return value; + } + + @Override + public Class getValueType() { + return valueType; + } + + public void assertIsWrapper(final BinaryData wrapper) { + assertEquals(getEndianness(), wrapper.getEndianness()); + assertEquals(getSize(), wrapper.getSize()); + } + } + } diff --git a/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskTest.java b/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskTest.java index 5ce42390b4e..8bee93c25f4 100644 --- a/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskTest.java +++ b/kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskTest.java @@ -137,20 +137,25 @@ private void testReadWrite(TaskProvider taskProvider, byte[] raw, Object javaVal } private void testRead(TaskProvider taskProvider, byte[] raw, Object javaValue) throws IOException { + testRead(taskProvider, raw, javaValue, DataType.BOOLEAN); + } + + private void testRead(TaskProvider taskProvider, byte[] raw, Object javaValue, DataType valueType) + throws IOException { int[] offsets = new int[] { 0, 7 }; for (final int offset : offsets) { - ChannelRecord record = ChannelRecord.createReadRecord("test", DataType.BOOLEAN); + ChannelRecord record = ChannelRecord.createReadRecord("test", valueType); byte[] buf = new byte[offset + raw.length]; System.arraycopy(raw, 0, buf, offset, raw.length); ChannelBlockTask task = taskProvider.get(record, offset, Mode.READ); ToplevelBlockTask parent = getToplevelBlockTask(buf, Mode.READ); parent.addChild(task); parent.run(); - assertEquals(ChannelFlag.SUCCESS, record.getChannelStatus().getChannelFlag()); + assertEquals(ChannelFlag.SUCCESS, task.getRecord().getChannelStatus().getChannelFlag()); if (!javaValue.getClass().isArray()) { - assertEquals(javaValue, record.getValue().getValue()); + assertEquals(javaValue, task.getRecord().getValue().getValue()); } else { - assertArrayEquals((byte[]) javaValue, (byte[]) record.getValue().getValue()); + assertArrayEquals((byte[]) javaValue, (byte[]) task.getRecord().getValue().getValue()); } } }