Browse Source

tbel: added some double methods

pull/11255/head
nick 2 years ago
parent
commit
2f838c4fbf
  1. 46
      common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
  2. 71
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

46
common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java

@ -170,7 +170,7 @@ public class TbUtils {
byte[].class, int.class, boolean.class))); byte[].class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class, boolean.class))); List.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
byte[].class, int.class, int.class, boolean.class))); byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class, int.class, boolean.class))); List.class, int.class, int.class, boolean.class)));
@ -186,10 +186,14 @@ public class TbUtils {
byte[].class, int.class))); byte[].class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, boolean.class))); byte[].class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class))); List.class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class, boolean.class))); List.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
double.class, int.class))); double.class, int.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
@ -798,11 +802,11 @@ public class TbUtils {
if (offset + length > data.length) { if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
} }
var bb = ByteBuffer.allocate(8); var bb = ByteBuffer.allocate(BYTES_LEN_LONG_MAX);
if (!bigEndian) { if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN); bb.order(ByteOrder.LITTLE_ENDIAN);
} }
bb.position(bigEndian ? 8 - length : 0); bb.position(bigEndian ? BYTES_LEN_LONG_MAX - length : 0);
bb.put(data, offset, length); bb.put(data, offset, length);
bb.position(0); bb.position(0);
return bb.getLong(); return bb.getLong();
@ -831,21 +835,21 @@ public class TbUtils {
public static float parseBytesToFloat(byte[] data, int offset, int length, boolean bigEndian) { public static float parseBytesToFloat(byte[] data, int offset, int length, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian); byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (length > BYTES_LEN_INT_MAX) { if (length > BYTES_LEN_INT_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!"); throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_INT_MAX + " bytes is allowed!");
} }
if (bytesToNumber.length < BYTES_LEN_INT_MAX) { if (bytesToNumber.length < BYTES_LEN_INT_MAX) {
byte[] extendedBytes = new byte[4]; byte[] extendedBytes = new byte[BYTES_LEN_INT_MAX];
Arrays.fill(extendedBytes, (byte) 0); Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length); System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes; bytesToNumber = extendedBytes;
} }
float floatValue = ByteBuffer.wrap(bytesToNumber).getFloat(); float floatValue = ByteBuffer.wrap(bytesToNumber).getFloat();
if (!Float.isNaN(floatValue)){ if (!Float.isNaN(floatValue)) {
return floatValue; return floatValue;
} else { } else {
long longValue = parseBytesToLong(bytesToNumber, offset, length, bigEndian); long longValue = parseBytesToLong(bytesToNumber, offset, length, bigEndian);
BigDecimal bigDecimalValue = new BigDecimal(longValue); BigDecimal bigDecimalValue = new BigDecimal(longValue);
return bigDecimalValue.floatValue(); return bigDecimalValue.floatValue();
} }
} }
@ -861,9 +865,33 @@ public class TbUtils {
return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian); return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian);
} }
public static double parseBytesToDouble(List data, int offset, int length, boolean bigEndian) {
return parseBytesToDouble(Bytes.toArray(data), offset, length, bigEndian);
}
public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, BYTES_LEN_LONG_MAX, bigEndian); return parseBytesToDouble(data, offset, BYTES_LEN_LONG_MAX, bigEndian);
return ByteBuffer.wrap(bytesToNumber).getDouble(); }
public static double parseBytesToDouble(byte[] data, int offset, int length, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (length > BYTES_LEN_LONG_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_LONG_MAX + " bytes is allowed!");
}
if (bytesToNumber.length < BYTES_LEN_LONG_MAX) {
byte[] extendedBytes = new byte[BYTES_LEN_LONG_MAX];
Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes;
}
double doubleValue = ByteBuffer.wrap(bytesToNumber).getDouble();
if (!Double.isNaN(doubleValue)) {
return doubleValue;
} else {
BigInteger bigInt = new BigInteger(1, bytesToNumber);
BigDecimal bigDecimalValue = new BigDecimal(bigInt);
return bigDecimalValue.doubleValue();
}
} }
private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) {

71
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

@ -30,6 +30,7 @@ import org.mvel2.execution.ExecutionArrayList;
import org.mvel2.execution.ExecutionHashMap; import org.mvel2.execution.ExecutionHashMap;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -279,36 +280,36 @@ public class TbUtilsTest {
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0))); Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false))); Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false)));
List<Byte> floatVaList = Bytes.asList(floatValByte); List<Byte> floatValList = Bytes.asList(floatValByte);
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0))); Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValList, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false))); Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValList, 0, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF} // 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF}
floatValByte = new byte[] {-1, -1, -1, -1}; floatValByte = new byte[]{-1, -1, -1, -1};
float floatExpectedBe = 4294.9673f; float floatExpectedBe = 4294.9673f;
float floatExpectedLe = 4.2949673E9f; float floatExpectedLe = 4.2949673E9f;
float actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true); float actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe/1000000)); Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, false))); Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, false)));
floatVaList = Bytes.asList(floatValByte); floatValList = Bytes.asList(floatValByte);
actualBe = TbUtils.parseBytesToFloat(floatVaList, 0); actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe/1000000)); Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatVaList, 0, false))); Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, false)));
// 2 143 289 344L == {0x7F, 0xC0, 0x00, 0x00} // 2 143 289 344L == {0x7F, 0xC0, 0x00, 0x00}
floatValByte = new byte[] {0x7F, (byte) 0xC0, (byte) 0xFF, 0x00}; floatValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
floatExpectedBe = 2143.3547f; floatExpectedBe = 2143.3547f;
floatExpectedLe = -3.984375f; floatExpectedLe = -3.984375f;
actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true); actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe/1000000)); Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 2,false))); Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 2, false)));
floatVaList = Bytes.asList(floatValByte); floatValList = Bytes.asList(floatValByte);
floatExpectedLe = 8372479.0f; floatExpectedLe = 8372479.0f;
actualBe = TbUtils.parseBytesToFloat(floatVaList, 0); actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe/1000000)); Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatVaList, 0, 3, false))); Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, 3, false)));
} }
@Test @Test
@ -385,9 +386,38 @@ public class TbUtilsTest {
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0))); Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false))); Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false)));
List<Byte> doubleVaList = Bytes.asList(doubleValByte); List<Byte> doubleValList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0))); Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValList, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false))); Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValList, 0, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
doubleValByte = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1};
double doubleExpectedBe = 18446.744073709553d;
double doubleExpectedLe = 1.8446744073709552E19d;
double actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, false)));
doubleValList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, TbUtils.parseBytesToDouble(doubleValList, 0) / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, false)));
doubleValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00, 0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
doubleExpectedBe = 2387013.651780523d;
doubleExpectedLe = 7.234601680440024E-304d;
actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
BigDecimal bigDecimal = new BigDecimal(actualBe);
// We move the decimal point to the left by 301 positions
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
doubleValList = Bytes.asList(doubleValByte);
doubleExpectedLe = 5.828674572203954E303d;
actualBe = TbUtils.parseBytesToDouble(doubleValList, 0);
bigDecimal = new BigDecimal(actualBe);
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, 5, false)));
} }
@Test @Test
@ -660,7 +690,8 @@ public class TbUtilsTest {
valueActual = TbUtils.parseHexToFloat(valueHexRev, false); valueActual = TbUtils.parseHexToFloat(valueHexRev, false);
Assertions.assertEquals(value, valueActual); Assertions.assertEquals(value, valueActual);
} }
// If the length is not equal to 8 characters, we process it as an integer (eg "0x0A" for 10.0f).
// If the length is not equal to 8 characters, we process it as an integer (eg "0x0A" for 10.0f).
@Test @Test
public void parseHexIntLongToFloat_Test() { public void parseHexIntLongToFloat_Test() {
Float valueExpected = 10.0f; Float valueExpected = 10.0f;

Loading…
Cancel
Save