diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitAND.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitAND.java new file mode 100644 index 0000000000..4c02ebb87e --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitAND.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitAND extends TwoArgBitwiseOperation +{ + public BitAND() + { + super("bitAND", "Bitwise AND (x, y)", (a, b) -> a & b); + } +} \ No newline at end of file diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitLeftShift.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitLeftShift.java new file mode 100644 index 0000000000..5e7d5e4fa4 --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitLeftShift.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitLeftShift extends TwoArgBitwiseOperation +{ + public BitLeftShift() + { + super("bitLeftShift", "Bitwise Left Shift (x, y)", (a, b) -> a << b); + } +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitNOT.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitNOT.java new file mode 100644 index 0000000000..4008ecdb70 --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitNOT.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitNOT extends OneArgBitwiseOperation +{ + public BitNOT() + { + super("bitNOT", "Bitwise NOT (x)", a -> ~a); + } +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitOR.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitOR.java new file mode 100644 index 0000000000..e9b8b0ee99 --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitOR.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitOR extends TwoArgBitwiseOperation +{ + public BitOR() + { + super("bitOR", "Bitwise OR (x, y)", (a, b) -> a | b); + } +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitRightShift.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitRightShift.java new file mode 100644 index 0000000000..a8e548b90c --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitRightShift.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitRightShift extends TwoArgBitwiseOperation +{ + public BitRightShift() + { + super("bitRightShift", "Bitwise Right Shift (x, y)", (a, b) -> a >> b); + } +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitXOR.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitXOR.java new file mode 100644 index 0000000000..6b3fea709e --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/BitXOR.java @@ -0,0 +1,9 @@ +package org.csstudio.apputil.formula.bitwise; + +public class BitXOR extends TwoArgBitwiseOperation +{ + public BitXOR() + { + super("bitXOR", "Bitwise XOR (x, y)", (a, b) -> a ^ b); + } +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/OneArgBitwiseOperation.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/OneArgBitwiseOperation.java new file mode 100644 index 0000000000..3a3556873f --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/OneArgBitwiseOperation.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2019-2020 Oak Ridge National Laboratory. + * 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 + ******************************************************************************/ +package org.csstudio.apputil.formula.bitwise; + +import java.util.List; + +import org.csstudio.apputil.formula.spi.FormulaFunction; +import org.epics.vtype.Alarm; +import org.epics.vtype.Display; +import org.epics.vtype.Time; +import org.epics.vtype.VDouble; +import org.epics.vtype.VType; +import org.phoebus.core.vtypes.VTypeHelper; + +/** Helper for SPI-provided `long operation(long)` + * @author Mathis Huriez + */ +@SuppressWarnings("nls") +class OneArgBitwiseOperation implements FormulaFunction +{ + @FunctionalInterface + public interface OneArgOperation + { + long calc(long arg); + } + + private final String name; + private final String description; + private final OneArgOperation operation; + + protected OneArgBitwiseOperation(final String name, final String description, final OneArgOperation operation) + { + this.name = name; + this.description = description; + this.operation = operation; + } + + @Override + public String getCategory() { + return "bitwise"; + } + + @Override + public String getName() + { + return name; + } + + @Override + public String getDescription() + { + return description; + } + + @Override + public List getArguments() + { + return List.of("x"); + } + + @Override + public VType compute(final VType... args) throws Exception + { + final double arg = VTypeHelper.toDouble(args[0]); + final long a = (long) arg; + if((double) a != arg) + throw new Exception("Operation " + getName() + + " takes integer type but received floating-point type"); + final long value = operation.calc(a); + return VDouble.of(value, Alarm.none(), Time.now(), Display.none()); + } + +} diff --git a/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/TwoArgBitwiseOperation.java b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/TwoArgBitwiseOperation.java new file mode 100644 index 0000000000..58b4ef7f74 --- /dev/null +++ b/core/formula/src/main/java/org/csstudio/apputil/formula/bitwise/TwoArgBitwiseOperation.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2019-2020 Oak Ridge National Laboratory. + * 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 + ******************************************************************************/ +package org.csstudio.apputil.formula.bitwise; + +import java.util.List; + +import org.csstudio.apputil.formula.spi.FormulaFunction; +import org.epics.vtype.Alarm; +import org.epics.vtype.Display; +import org.epics.vtype.Time; +import org.epics.vtype.VDouble; +import org.epics.vtype.VType; +import org.phoebus.core.vtypes.VTypeHelper; + +/** Helper for SPI-provided `long operation(long, long)` + * @author Mathis Huriez + */ +@SuppressWarnings("nls") +class TwoArgBitwiseOperation implements FormulaFunction +{ + @FunctionalInterface + public interface TwoArgOperation + { + long calc(long a, long b); + } + + private final String name; + private final String description; + private final TwoArgOperation operation; + + protected TwoArgBitwiseOperation(final String name, final String description, final TwoArgOperation operation) + { + this.name = name; + this.description = description; + this.operation = operation; + } + + @Override + public String getCategory() { + return "bitwise"; + } + + @Override + public String getName() + { + return name; + } + + @Override + public String getDescription() + { + return description; + } + + @Override + public List getArguments() + { + return List.of("x", "y"); + } + + @Override + public VType compute(final VType... args) throws Exception + { + final double arg_a = VTypeHelper.toDouble(args[0]); + final double arg_b = VTypeHelper.toDouble(args[1]); + final long a = (long) arg_a, b = (long) arg_b; + // Check if the conversion is accurate, else, send an exception + if((double) a != arg_a || (double) b != arg_b) + throw new Exception("Operation " + getName() + + " takes integer types but received floating-point types"); + final long value = operation.calc(a, b); + return VDouble.of(value, Alarm.none(), Time.now(), Display.none()); + } +} diff --git a/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction b/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction index 767b83f54e..7ac24eb076 100644 --- a/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction +++ b/core/formula/src/main/resources/META-INF/services/org.csstudio.apputil.formula.spi.FormulaFunction @@ -11,6 +11,7 @@ org.csstudio.apputil.formula.math.ExpM1 org.csstudio.apputil.formula.math.Floor org.csstudio.apputil.formula.math.Log org.csstudio.apputil.formula.math.Log10 +org.csstudio.apputil.formula.math.Round org.csstudio.apputil.formula.math.Sin org.csstudio.apputil.formula.math.SinH org.csstudio.apputil.formula.math.Sqrt @@ -55,6 +56,14 @@ org.csstudio.apputil.formula.array.ArrayStatsFunction org.csstudio.apputil.formula.array.ArrayMaxFunction org.csstudio.apputil.formula.array.ArrayMinFunction +# Bitwise Operation +org.csstudio.apputil.formula.bitwise.BitAND +org.csstudio.apputil.formula.bitwise.BitOR +org.csstudio.apputil.formula.bitwise.BitXOR +org.csstudio.apputil.formula.bitwise.BitNOT +org.csstudio.apputil.formula.bitwise.BitLeftShift +org.csstudio.apputil.formula.bitwise.BitRightShift + # Alarm org.csstudio.apputil.formula.alarm.HighestSeverityFunction org.csstudio.apputil.formula.alarm.MajorAlarmFunction diff --git a/core/formula/src/test/java/org/csstudio/apputil/formula/FormulaUnitTest.java b/core/formula/src/test/java/org/csstudio/apputil/formula/FormulaUnitTest.java index c142b74abe..34fadd7872 100644 --- a/core/formula/src/test/java/org/csstudio/apputil/formula/FormulaUnitTest.java +++ b/core/formula/src/test/java/org/csstudio/apputil/formula/FormulaUnitTest.java @@ -194,6 +194,24 @@ public void testFunctions() throws Exception { // usually, should NOT get the same number twice... assertTrue(rnd != rnd2); } + + f = new Formula("round(12.3)"); + assertEquals(12, VTypeHelper.toDouble(f.eval()), epsilon); + + f = new Formula("bitOR(5, 7)"); + assertEquals(7, VTypeHelper.toDouble(f.eval()), epsilon); + + f = new Formula("bitXOR(5, 7)"); + assertEquals(2, VTypeHelper.toDouble(f.eval()), epsilon); + + f = new Formula("bitRightShift(2, 4)"); + assertEquals(0, VTypeHelper.toDouble(f.eval()), epsilon); + + f = new Formula("bitRightShift(4, 2)"); + assertEquals(1, VTypeHelper.toDouble(f.eval()), epsilon); + + f = new Formula("bitNOT(5)"); + assertEquals(-6, VTypeHelper.toDouble(f.eval()), epsilon); } @Test @@ -257,6 +275,9 @@ public void testErrors() throws Exception { f = new Formula("sqrt(-1)"); assertTrue(Double.isNaN(VTypeHelper.toDouble(f.eval()))); + + f = new Formula("bitXOR(5.3, 7)"); + assertTrue(Double.isNaN(VTypeHelper.toDouble(f.eval()))); } @Test