*
*/
public class Expression {
+ protected static Expression instance = null;
+
+ /**
+ * Evaluate a formula and returns the long value.
+ *
+ * <b>Note</b>:
+ * <ul>
+ * <li>not thread save: uses a singleton instance</li>
+ * <li>Variables defined in the formula live in singleton "forever"</li>
+ * </ul>
+ *
+ * @param text
+ * formula text
+ * @return the result of the formula as long
+ * @throws ExpressionException
+ */
+ public static long asLong(final String text) throws ExpressionException {
+ final Variant result = Expression.getInstance().expr(text);
+ if (!result.isBasicType(DataType.LONG)) {
+ throw new VariantException(
+ String.format(I18N.tr("Expected type: INTEGER found: %s: %s"), result.getType().name(), text));
+ }
+ return result.getLongValue();
+ }
+
+ /**
+ * Evaluate a formula and returns the long value.
+ *
+ * <b>Note</b>:
+ * <ul>
+ * <li>not thread save: uses a singleton instance</li>
+ * <li>error messages will be suppressed</li>
+ * <li>Variables defined in the formula live in singleton "forever"</li>
+ * </ul>
+ *
+ * @param text
+ * formula text
+ * @param defaultValue
+ * result if the formula contain errors
+ * @return <i>defaultValue</i>: error occurred<br>
+ * otherwise: the result of the formula as long
+ */
+ public static long asLong(final String text, long defaultValue) {
+ long rc = defaultValue;
+ Variant result;
+ try {
+ result = Expression.getInstance().expr(text);
+ if (result.isType(DataType.LONG)) {
+ rc = result.getLongValue();
+ }
+ } catch (final ParserException e) {
+ // messages are suppressed
+ }
+ return rc;
+ }
+
+ /**
+ * @return the instance
+ */
+ public static Expression getInstance() {
+ if (Expression.instance == null) {
+ Expression.instance = new Expression("");
+ }
+ return Expression.instance;
+ }
+
protected Scanner scanner;
protected HashMap<String, Variable> variables = new HashMap<>();
protected Stack<Variant> values = new Stack<>();
}
this.values.push(value1);
Token token;
- while (!(token = this.scanner.nextNotSpaceToken()).isType(TokenType.END_OF_STRING)) {
+ boolean again = true;
+ while (again && !(token = this.scanner.nextNotSpaceToken()).isType(TokenType.END_OF_STRING)) {
if (token.isOp(OpCode.RIGHT_PARENT)) {
break;
}
final OpCode op = token.getOpCode();
Variant value2;
final Token tokenOp = token.copy();
- if (op == OpCode.ASSIGN) {
- if (!value1.isType(DataType.VARIABLE)) {
+ if (op == OpCode.ASSIGNMENT) {
+ if (!value1.isRValue()) {
throw new ParserException(I18N.tr("Assignment misses a rvalue (e.g. a variable) on the left side"),
token);
}
value2 = expr();
+ // we may not read the next token!
+ again = false;
} else {
- value2 = term();
+ if ((value2 = term()) != null) {
+ value2 = value2.lValue();
+ }
}
if (value2 == null) {
throw new ParserException(I18N.tr("unexpected end of string"), this.scanner.getLastToken(), false);
reduceStack();
}
value1 = this.values.pop();
- return value1;
+ return value1.lValue();
}
/**
return rc;
}
+ /**
+ * @return the scanner
+ */
+ public Scanner getScanner() {
+ return this.scanner;
+ }
+
/**
* Finishes the last stored binary operation.
*
final Variant operand1 = this.values.lastElement();
final Token op = this.operators.pop();
try {
+ final OpCode op2 = op.getOpCode();
+ if (op2 != OpCode.ASSIGNMENT && operand1.isRValue()) {
+ // We may not change the variable value, we change it to a
+ // lvalue:
+ operand1.redefine(operand1.lValueImmutable());
+ }
operand1.binaryOperation(op.getOpCode(), operand2);
} catch (final VariantException e) {
// transform in a message with position info:
--- /dev/null
+/**
+ *
+ */
+package de.republib.expr;
+
+/**
+ * Base class of all exception used in the package de.republib.expr.
+ *
+ * @author hm
+ *
+ */
+public class ExpressionException extends Exception {
+ /**
+ * Constructor.
+ *
+ * @param message
+ * describes the reason of the exception
+ */
+ public ExpressionException(final String message) {
+ super(message);
+ }
+}
package de.republib.expr;
public enum OpCode {
- UNDEF(0), ASSIGN(1, false, true), //
+ UNDEF(0), ASSIGNMENT(1, false, true), //
PLUS(10, true), MINUS(10, true), //
TIMES(11), DIV(11), MOD(11), //
POWER(12), //
package de.republib.expr;
/**
- * Handles scanner errors like "unknown token".
+ * Handles scanner and parser errors like "unknown token".
*
* @author hm
*
*/
-public class ParserException extends Exception {
+public class ParserException extends ExpressionException {
private static final long serialVersionUID = 1L;
/**
op = OpCode.RIGHT_PARENT;
break;
case '=':
- op = OpCode.ASSIGN;
+ op = OpCode.ASSIGNMENT;
break;
default:
rc = false;
*/
package de.republib.expr;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import de.republib.util.I18N;
/**
* @author hm
*
*/
-public class Variant {
+public class Variant implements Cloneable {
+ private static final Logger logger = LoggerFactory.getLogger(Variant.class);
protected DataType type;
protected long longValue = Long.MIN_VALUE;
protected double doubleValue = Double.NaN;
*/
public long asLong(long defaultValue) {
long rc = defaultValue;
- if (this.longValue != Long.MIN_VALUE) {
- rc = this.longValue;
+ final Variant lValue = this.lValueImmutable();
+ // Is the cache defined?
+ if (lValue.longValue != Long.MIN_VALUE) {
+ rc = lValue.longValue;
} else {
- switch (this.type) {
+ // fill the cache:
+ switch (lValue.type) {
case BOOLEAN:
- rc = this.longValue = this.boolValue ? 1L : 0L;
+ rc = lValue.longValue = lValue.boolValue ? 1L : 0L;
break;
case DOUBLE:
- rc = this.longValue = Math.round(this.doubleValue);
+ rc = lValue.longValue = Math.round(lValue.doubleValue);
break;
case LONG:
- rc = this.longValue;
+ rc = lValue.longValue;
break;
case STRING: {
try {
- final Token token = new Scanner(this.stringValue).nextNotSpaceToken();
+ final Token token = new Scanner(lValue.stringValue).nextNotSpaceToken();
if (token.isType(TokenType.INTEGER)) {
- rc = this.longValue = token.getLongValue();
+ rc = lValue.longValue = token.getLongValue();
}
} catch (final ParserException e) {
// do nothing
break;
}
case VARIABLE:
- rc = this.longValue = this.variableValue.getValue().asLong(defaultValue);
+ Variant.logger.error("lValue has type VARIABLE: value: " + lValue.toString());
break;
default:
+ Variant.logger.error("unknown Variant.type: " + lValue.type.name());
break;
}
}
* @return a string representation of the value
*/
public String asString() {
- if (this.stringValue == null) {
- switch (this.type) {
+ final Variant lValue = lValueImmutable();
+ if (lValue.stringValue == null) {
+ switch (lValue.type) {
case BOOLEAN:
- this.stringValue = this.boolValue ? "true" : "false";
+ lValue.stringValue = lValue.boolValue ? "true" : "false";
break;
case DOUBLE:
- this.stringValue = String.valueOf(this.doubleValue);
+ lValue.stringValue = String.valueOf(lValue.doubleValue);
break;
case LONG:
- this.stringValue = String.valueOf(this.longValue);
+ lValue.stringValue = String.valueOf(lValue.longValue);
break;
case OBJECT:
- this.stringValue = this.objectValue == null ? "" : this.objectValue.toString();
+ lValue.stringValue = lValue.objectValue == null ? "" : lValue.objectValue.toString();
break;
case VARIABLE:
- this.stringValue = this.variableValue.getValue().asString();
+ Variant.logger.error("lValue has type VARIABLE: value: " + lValue.toString());
break;
case STRING:
default:
- this.stringValue = "";
+ lValue.stringValue = "";
break;
}
}
- return this.stringValue;
+ return lValue.stringValue;
}
/**
*/
Variant binaryOperation(OpCode op, Variant operand) throws VariantException {
switch (op) {
- case ASSIGN:
+ case ASSIGNMENT:
if (this.type != DataType.VARIABLE) {
throw new VariantException(I18N.tr("Assignment misses a rvalue (e.g. a variable) on the left side"));
}
return this;
}
+ /**
+ * Copies the instance.
+ *
+ * @return a flat copy of the instance
+ */
+ public Variant copy() {
+ Variant rc = null;
+ try {
+ rc = (Variant) this.clone();
+ } catch (final CloneNotSupportedException e) {
+ Variant.logger.error("cloning failed: ", e);
+ }
+ return rc;
+ }
+
/**
* @return the boolValue
*/
return this.variableValue;
}
+ /**
+ * Returns whether the instance has a given type
+ *
+ * It will be tested the data type at the end of the reference chain (if
+ * available), e.g. if the instance is a variable the data type if the
+ * variable is tested (not the type VARIABLE).
+ *
+ * @param type
+ * data type to test
+ * @return <i>true</i>: the instance's data type has the given type
+ */
+ public boolean isBasicType(DataType type) {
+ Variant value = this;
+ while (value.isType(DataType.VARIABLE)) {
+ value = this.variableValue.getValue();
+ }
+ final boolean rc = value.isType(type);
+ return rc;
+ }
+
+ /**
+ * Returns whether the instance can be a right side of an assignment, e.g. a
+ * variable.
+ *
+ * @return <i>true</i>: the instance is a rvalue
+ */
+ public boolean isRValue() {
+ final boolean rc = this.type == DataType.VARIABLE;
+ return rc;
+ }
+
/**
* Tests whether the data type is equal to a given type.
*
return this.type == expected;
}
+ /**
+ * Returns the "left value" of the value: variables will be dereferenced.
+ *
+ * @return the value at the end of the reference chain (value of the
+ * variable of the variable...)
+ */
+ public Variant lValue() {
+ Variant rc = this;
+ while (rc.isType(DataType.VARIABLE)) {
+ rc = this.variableValue.getValue();
+ if (!rc.isType(DataType.VARIABLE)) {
+ rc = rc.copy();
+ break;
+ }
+ }
+ return rc;
+ }
+
+ /**
+ * Returns the "left value" of the value: variables will be dereferenced.
+ *
+ * Note: never change the result: it may be the value of a variable.
+ *
+ * @return the value at the end of the reference chain (value of the
+ * variable of the variable...)
+ */
+ protected Variant lValueImmutable() {
+ Variant rc = this;
+ while (rc.isType(DataType.VARIABLE)) {
+ rc = this.variableValue.getValue();
+ }
+ return rc;
+ }
+
/**
* Finds the largest exponent for a given base.
*
* @author hm
*
*/
-public class VariantException extends Exception {
+public class VariantException extends ExpressionException {
private static final long serialVersionUID = 1L;
/**
--- /dev/null
+/**
+ *
+ */
+package de.republib.gui;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Vector;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import de.republib.expr.Expression;
+import de.republib.expr.ParserException;
+import de.republib.util.Announcer;
+
+class HistoryModel extends DefaultComboBoxModel<String> {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private final int maxEntries;
+
+ /**
+ * Constructor.
+ */
+ public HistoryModel(int maxEntries) {
+ super(new Vector<String>());
+ this.maxEntries = maxEntries;
+ }
+
+ /**
+ * Adds an entry to the history.
+ *
+ * Moves the item to the first place if it exists in the list. Limits the
+ * list size.
+ *
+ * @param item
+ * new item
+ */
+ public void add(String item) {
+ super.removeElement(item);
+ int size;
+ while ((size = super.getSize()) >= this.maxEntries) {
+ super.removeElementAt(size - 1);
+ }
+ super.insertElementAt(item, 0);
+ }
+}
+
+/**
+ * Implements a field for numbers with formula evaluation and history in
+ * listbox.
+ *
+ * @author hm
+ *
+ */
+public class NumberField extends JComboBox<String> implements FocusListener {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger logger = LoggerFactory.getLogger(NumberField.class);
+ Vector<String> history;
+ protected Expression expression;
+ protected Announcer announcer;
+ long longValue;
+ long defaultValue;
+
+ /**
+ * Constructor.
+ *
+ * @param text
+ * the first combobox text
+ * @param defaultValue
+ * the long value if an error occurres
+ * @param maxEntries
+ * maximal count of list entries
+ * @param expression
+ * <i>null</i> or the formula interpreter
+ * @param announcer
+ * displays the error messages
+ */
+ public NumberField(String text, long defaultValue, int maxEntries, Expression expression, Announcer announcer) {
+ super(new HistoryModel(maxEntries));
+ this.expression = expression == null ? new Expression("") : expression;
+ this.announcer = announcer;
+ this.defaultValue = defaultValue;
+ this.setEditable(true);
+ ((HistoryModel) this.getModel()).add(text);
+ // Transform the formula to a long value:
+ focusLost(null);
+ getEditor().getEditorComponent().addFocusListener(this);
+ this.setSelectedItem(text);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
+ */
+ @Override
+ public void focusGained(FocusEvent e) {
+ NumberField.logger.debug("NumberField: focus gained");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
+ */
+ @Override
+ public void focusLost(FocusEvent event) {
+ final String formula = (String) this.getSelectedItem();
+ if (formula != null) {
+ try {
+ this.longValue = this.expression.expr(formula).asLong(this.defaultValue);
+ ((HistoryModel) getModel()).add(formula);
+ } catch (final ParserException e) {
+ this.announcer.say(Announcer.ERROR, e.getLocalizedMessage());
+ }
+ }
+ }
+
+ /**
+ * @return the longValue
+ */
+ public int getIntValue() {
+ return this.longValue > Integer.MAX_VALUE ? Integer.MAX_VALUE
+ : this.longValue < Integer.MIN_VALUE ? Integer.MIN_VALUE : (int) this.longValue;
+ }
+
+ /**
+ * @return the longValue
+ */
+ public long getLongValue() {
+ return this.longValue;
+ }
+
+}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
} catch (final UnknownHostException e) {
this.logger.error(String.format("unknown server: %s:%d", host, port));
} catch (final IOException e) {
- this.logger.error(String.format("cannot connect to %s:%d", host, port), e);
+ if ((e instanceof ConnectException)) {
+ this.logger.error(String.format("cannot connect to %s:%d", host, port));
+ } else {
+ this.logger.error(String.format("cannot connect to %s:%d", host, port), e);
+ }
}
}
+ /**
+ * @return the active
+ */
+ public boolean getActive() {
+ return this.active;
+ }
+
/**
* @return the host
*/
}
} catch (final IOException e) {
this.logger.error("TcpClient.receive():", e);
+ this.active = false;
}
return buffer;
}
}
try {
this.outStream.write(message.getBuffer(), 0, message.getLength());
+ this.active = false;
} catch (final IOException e) {
this.logger.error(String.format("send(%s, %d)", message.toUtf8(4), message.getLength()), e);
+ this.active = false;
}
}
}
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
+import de.republib.expr.Expression;
import de.republib.gui.GuiUtils;
import de.republib.gui.MultiChannelSheet;
import de.republib.pinet.GpioClient;
private JTextField textFieldColumns;
private JTabbedPane tabbedPane;
private int channelCount = 8;
+ private final Expression expression = new Expression("");
/**
* Constructor.
return this.client;
}
+ /**
+ * @return the expression
+ */
+ public Expression getExpression() {
+ return this.expression;
+ }
+
/**
* Populates the main panel with widgets.
*
}
+ /**
+ * Tries to establish a TCP connection.
+ *
+ * @return <i>true</i>: the connection is established
+ */
+ public boolean reconnect() {
+ final boolean rc = this.client.getActive();
+ final String host = this.textFieldServer.getText();
+ final int port = GuiUtils.numberOf(this.textFieldPort, 15000, true);
+ if (!rc) {
+ this.client = new GpioClient(host, port);
+ }
+ if (!rc) {
+ say(Announcer.ERROR, String.format(I18N.tr("%s:%d is not reachable"), host, port));
+ }
+ return rc;
+ }
+
public void run() {
// Display the window.
this.frame.pack();
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import de.republib.gui.GuiUtils;
+import de.republib.gui.NumberField;
import de.republib.pinet.Function;
import de.republib.pinet.GpioClient;
import de.republib.pinet.PinNumber;
add(this.panelOutputBlinkData = new OutputBlinkPanel(this.center, panelPinData));
this.panelOutputBlinkData.setVisible(false);
add(this.panelOutputPwmData = new OutputPwmPanel(this.center, panelPinData));
- this.panelOutputPwmData.setVisible(true);
+ this.panelOutputPwmData.setVisible(false);
add(this.panelInputData = new InputPanel(this.center, panelPinData));
this.panelInputData.setVisible(false);
add(this.panelInputPwmData = new InputPwmPanel(this.center, panelPinData));
private static final long serialVersionUID = 1L;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private JComboBox<String> comboChannel;
- private JTextField textInterval;
+ private NumberField comboInterval;
private final ControlCenter center;
private final PinPanel pinData;
JButton buttonRun;
add(this.comboChannel = new JComboBox<String>(), "wrap");
this.center.addChannelComboBox(this.comboChannel);
add(new JLabel(I18N.tr("Interval:")));
- add(this.textInterval = new JTextField("0"), "wrap");
+ add(this.comboInterval = new NumberField("1000", 1000, 16, center.getExpression(), center), "wrap");
add(this.buttonRun = new JButton(I18N.tr("Start")), "span 2, wrap");
this.buttonRun.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.buttonRun) {
- final int interval = GuiUtils.numberOf(this.textInterval, 1000, true);
+ final int interval = this.comboInterval.getIntValue();
final int channel = this.comboChannel.getSelectedIndex();
this.logger.info(String.format("channel: %d interval: %d", channel, interval));
}
private static final long serialVersionUID = 1L;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private JComboBox<String> comboChannel;
- private JTextField textFieldClock;
- private JTextField textFieldSteps;
+ private NumberField comboClock;
+ private NumberField comboSteps;
private final ControlCenter center;
private final PinPanel pinData;
private JButton buttonRun;
add(this.comboChannel = new JComboBox<String>(), "wrap");
this.center.addChannelComboBox(this.comboChannel);
add(new JLabel(I18N.tr("Clock:")));
- add(this.textFieldClock = new JTextField("1000"), "wrap");
+ add(this.comboClock = new NumberField("1000*1000", 1000 * 1000, 16, center.getExpression(), center), "wrap");
add(new JLabel(I18N.tr("Period:")));
- add(this.textFieldSteps = new JTextField("1024"), "wrap");
+ add(this.comboSteps = new NumberField("1024", 1024, 16, center.getExpression(), center), "wrap");
add(this.buttonRun = new JButton(I18N.tr("Start")), "span 2, wrap");
this.buttonRun.addActionListener(this);
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.buttonRun) {
final int channel = this.comboChannel.getSelectedIndex();
- final int clock = GuiUtils.numberOf(this.textFieldClock, 1000, true);
- final int steps = GuiUtils.numberOf(this.textFieldSteps, 1024, true);
+ final int clock = this.comboClock.getIntValue();
+ final int steps = this.comboSteps.getIntValue();
this.logger.info(String.format("channel: %d clock: %d steps: %d", channel, clock, steps));
}
}
private static final long serialVersionUID = 1L;
// private final Logger logger = LoggerFactory.getLogger(OutputData.class);
private JComboBox<String> comboMode;
- private JTextField textCount;
- private JTextField textHigh;
- private JTextField textLow;
+ private NumberField comboCount;
+ private NumberField comboHigh;
+ private NumberField ComboLow;
private JButton buttonRun;
private final ControlCenter center;
private final PinPanel pinData;
this.pinData = pinData;
add(new JLabel(I18N.tr("Blink parameters:")), "span 2, wrap");
add(new JLabel(I18N.tr("Count:")));
- add(this.textCount = new JTextField("10"), "wrap");
+ add(this.comboCount = new NumberField("10", 10, 16, center.getExpression(), center), "wrap");
add(new JLabel(I18N.tr("High:")));
- add(this.textHigh = new JTextField("500"), "wrap");
+ add(this.comboHigh = new NumberField("500", 500, 16, center.getExpression(), center), "wrap");
add(new JLabel(I18N.tr("Low:")));
- add(this.textLow = new JTextField("500"), "wrap");
+ add(this.ComboLow = new NumberField("500", 500, 16, center.getExpression(), center), "wrap");
add(this.buttonRun = new JButton(I18N.tr("Start")), "span 2");
this.buttonRun.addActionListener(this);
}
if (e.getSource() == this.buttonRun) {
final GpioClient client = this.center.getClient();
final PinButton current = this.pinData.getCurrentPin();
- final int count = GuiUtils.numberOf(this.textCount, 10, true);
- final int high = GuiUtils.numberOf(this.textHigh, 500, true);
- final int low = GuiUtils.numberOf(this.textLow, 500, true);
- this.center.say(Announcer.LOG,
- String.format(I18N.tr("blinking started on pin %d"), current.getPinNumber().getNumber()));
- final DynBytes answer = client.blink(current.getPinNumber(), count, high, low);
- if (answer.startsWith("OK")) {
+ final int count = this.comboCount.getIntValue();
+ final int high = this.comboHigh.getIntValue();
+ final int low = this.ComboLow.getIntValue();
+ if (this.center.reconnect()) {
this.center.say(Announcer.LOG,
- String.format(I18N.tr("pin %d blinks %d times"), current.getPinNumber().getNumber(), count));
+ String.format(I18N.tr("blinking started on pin %d"), current.getPinNumber().getNumber()));
+ final DynBytes answer = client.blink(current.getPinNumber(), count, high, low);
+ if (answer.startsWith("OK")) {
+ this.center.say(Announcer.LOG, String.format(I18N.tr("pin %d blinks %d times"),
+ current.getPinNumber().getNumber(), count));
+ }
}
} else if (e.getSource() == this.comboMode) {
static String[] modes = { I18N.tr("constant"), I18N.tr("sin"), I18N.tr("falling slope"), I18N.tr("rising slope"),
I18N.tr("dual slope") };
private JComboBox<String> comboMode;
- private JTextField textFieldPeriod;
- private JTextField textFieldStartValue;
- private JTextField textFieldFunctionSteps;
- private JTextField textFieldCount;
+ private NumberField comboPeriod;
+ private NumberField comboStartValue;
+ private NumberField comboFunctionSteps;
+ private NumberField comboCount;
private JButton buttonRun;
private final ControlCenter center;
private final PinPanel pinData;
this.pinData = pinData;
add(new JLabel(I18N.tr("Output Parameters:")), "span 2, wrap");
add(new JLabel(I18N.tr("Clock:")));
- add(this.textFieldPeriod = new JTextField("10000"), "wrap");
- this.textFieldPeriod.setToolTipText(I18N.tr("Duration of the pwm signal in microseconds"));
+ add(this.comboPeriod = new NumberField("1000*1000", 1000 * 1000, 16, center.getExpression(), center), "wrap");
+ this.comboPeriod.setToolTipText(I18N.tr("Duration of the pwm signal in microseconds"));
add(new JLabel(I18N.tr("Start value:")));
- add(this.textFieldStartValue = new JTextField("0"), "wrap");
- this.textFieldStartValue.setToolTipText(I18N.tr("First pwm value, multiplied with 1E4, e.g. 223 means 0.0223"));
+ add(this.comboStartValue = new NumberField("0", 0, 16, center.getExpression(), center), "wrap");
+ this.comboStartValue.setToolTipText(I18N.tr("First pwm value, multiplied with 1E4, e.g. 223 means 0.0223"));
add(new JLabel(I18N.tr("Function:")));
add(this.comboMode = new JComboBox<String>(OutputPwmPanel.modes), "wrap");
this.comboMode.setToolTipText(I18N.tr("A periodic function defining the pwm values."));
add(new JLabel(I18N.tr("Function steps:")));
- add(this.textFieldFunctionSteps = new JTextField("20"), "wrap");
- this.textFieldFunctionSteps.setToolTipText(I18N
+ add(this.comboFunctionSteps = new NumberField("20", 20, 16, center.getExpression(), center), "wrap");
+ this.comboFunctionSteps.setToolTipText(I18N
.tr("Count of pwm periods building a 'function period': After this time the pwm values are repeated."));
add(new JLabel(I18N.tr("Count:")));
- add(this.textFieldCount = new JTextField("2147483647"), "wrap");
+ add(this.comboCount = new NumberField("2**31", Integer.MAX_VALUE, 16, center.getExpression(), center), "wrap");
add(this.buttonRun = new JButton(I18N.tr("Start")), "span 2");
this.buttonRun.addActionListener(this);
if (e.getSource() == this.buttonRun) {
final GpioClient client = this.center.getClient();
final PinButton current = this.pinData.getCurrentPin();
- final int period = GuiUtils.numberOf(this.textFieldPeriod, 10000, true);
- final double startValue = GuiUtils.numberOf(this.textFieldStartValue, 0, true) / 1E4;
+ final int period = this.comboPeriod.getIntValue();
+ final double startValue = this.comboStartValue.getIntValue() / 1E4;
final int mode = this.comboMode.getSelectedIndex();
final Function function = Function.findById(mode);
- final int functionSteps = GuiUtils.numberOf(this.textFieldFunctionSteps, 0, true);
- final int count = GuiUtils.numberOf(this.textFieldCount, 0, true);
-
- this.center.say(Announcer.LOG,
- String.format(I18N.tr("PWM output: period: %d start: %f Mode: %s"), period, startValue, mode));
- final DynBytes answer = client.pwmOutput(current.getPinNumber(), period, startValue, function,
- functionSteps, count);
- if (answer.startsWith("OK")) {
+ final int functionSteps = this.comboFunctionSteps.getIntValue();
+ final int count = this.comboCount.getIntValue();
+ if (this.center.reconnect()) {
this.center.say(Announcer.LOG,
- String.format(I18N.tr("pin %d puts pwm %d times"), current.getPinNumber().getNumber(), count));
+ String.format(I18N.tr("PWM output: period: %d start: %f Mode: %s"), period, startValue, mode));
+ final DynBytes answer = client.pwmOutput(current.getPinNumber(), period, startValue, function,
+ functionSteps, count);
+ if (answer.startsWith("OK")) {
+ this.center.say(Announcer.LOG, String.format(I18N.tr("pin %d puts pwm %d times"),
+ current.getPinNumber().getNumber(), count));
+ }
}
}
}
public static final int MODE_COUNT = PinButton.MODE_FOCUS + 1;
static ImageIcon[] icons = null;
private final Logger logger = LoggerFactory.getLogger(PinButton.class);
- private JLabel labelPin;
private final PinNumber pinNumber;
private final String title;
private String nickname;
this.logger.debug(
"actionPerformed(); changing mode: " + index + " isOutPwm: " + String.valueOf(isOutputPWM));
this.currentPin.setMode(index);
- this.parent.getGpioSettings().getPanelOutputBlinkData()
- .setVisible(index == PinButton.MODE_OUTPUT_BLINK);
+ boolean visible = index == PinButton.MODE_OUTPUT_BLINK;
+ this.parent.getGpioSettings().getPanelOutputBlinkData().setVisible(visible);
this.parent.getGpioSettings().getPanelOutputPwmData().setVisible(isOutputPWM);
- this.parent.getGpioSettings().getPanelInputData().setVisible(index == PinButton.MODE_INPUT);
- this.parent.getGpioSettings().getPanelInputPwmData().setVisible(index == PinButton.MODE_INPUT_PWM);
+ visible = index == PinButton.MODE_INPUT;
+ this.parent.getGpioSettings().getPanelInputData().setVisible(visible);
+ visible = index == PinButton.MODE_INPUT_PWM;
+ this.parent.getGpioSettings().getPanelInputPwmData().setVisible(visible);
}
}
-
}
/**
Assert.assertEquals(result.getLongValue(), 1L);
}
+ @Test
+ void shouldConvertToLong() throws ExpressionException {
+ Expression.getInstance();
+ Assert.assertEquals(Expression.asLong("1+2*3**4"), 163L);
+ // error should throw an exception:
+ try {
+ Expression.asLong("'x'");
+ Assert.fail("missing exception");
+ } catch (final ExpressionException e) {
+ Assert.assertTrue(e.getMessage().indexOf("INTEGER") > 0);
+ }
+ // suppressed exception:
+ Assert.assertEquals(Expression.asLong("'x'", -123L), -123L);
+ }
+
@Test
public void shouldFindVariable() {
final Expression expr = new Expression("");
}
@Test
- public void shouldWorkExpr() throws ParserException {
+ public void shouldWorkLongExpr() throws ParserException {
final Expression expr = new Expression("1 + 2*3");
Variant result = expr.expr();
Assert.assertEquals(result.getType(), DataType.LONG);
Assert.assertEquals(result.getType(), DataType.LONG);
Assert.assertEquals(result.getLongValue(), 3L);
}
+
+ @Test
+ public void shouldWorkVariables() throws ExpressionException {
+ // Variables remains in the singleton instance.
+ // assignment.
+ Assert.assertEquals(Expression.asLong("(a=5)"), 5L);
+ Assert.assertEquals(Expression.asLong("a=47"), 47L);
+ Assert.assertEquals(Expression.asLong("a=b=0x47"), 0x47L);
+ Assert.assertEquals(Expression.asLong("(One=1)+(e2=e3=2*3**4)"), 163L);
+ Assert.assertEquals(Expression.asLong("One"), 1L);
+ Assert.assertEquals(Expression.asLong("e2"), 162L);
+ Assert.assertEquals(Expression.asLong("e3"), 162L);
+ Assert.assertEquals(Expression.asLong("One+e2*9-e3"), 1L + 9 * 162 - 162);
+ Assert.assertEquals(Expression.asLong("One"), 1L);
+ Assert.assertEquals(Expression.asLong("e2"), 162L);
+ Assert.assertEquals(Expression.asLong("e3"), 162L);
+ }
}
Assert.assertEquals(varString.asString(), "Hi!");
}
+ @Test
+ public void shouldWorkLValue() {
+ final Variable var2 = new Variable("v2");
+ var2.getValue().redefineLong(44L);
+ final Variant val2 = new Variant(var2);
+
+ final Variable var1 = new Variable("v1");
+ var1.getValue().redefine(val2);
+ final Variant val1 = new Variant(var1);
+
+ Assert.assertTrue(val2.isType(DataType.VARIABLE));
+ Assert.assertTrue(val1.isType(DataType.VARIABLE));
+ Assert.assertTrue(val1.getVariableValue().getValue().isType(DataType.VARIABLE));
+ Assert.assertTrue(val1.isBasicType(DataType.LONG));
+ }
+
@Test
public void shouldWorkUnaryOpNot() throws VariantException {
final Variant var1 = new Variant(true);