mirror of
https://github.com/arduino/Arduino.git
synced 2025-03-15 12:29:26 +01:00
Adding plotting functionality to the editor
This commit is contained in:
parent
1d8fbd4b5d
commit
71f9d67a51
@ -3,6 +3,7 @@ package processing.app;
|
|||||||
import static processing.app.I18n._;
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
@ -15,15 +16,10 @@ import java.awt.event.WindowEvent;
|
|||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
@ -37,19 +33,11 @@ import processing.app.legacy.PApplet;
|
|||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
||||||
|
|
||||||
protected final JLabel noLineEndingAlert;
|
|
||||||
protected TextAreaFIFO textArea;
|
|
||||||
protected JScrollPane scrollPane;
|
|
||||||
protected JTextField textField;
|
|
||||||
protected JButton sendButton;
|
|
||||||
protected JCheckBox autoscrollBox;
|
|
||||||
protected JComboBox lineEndings;
|
|
||||||
protected JComboBox serialRates;
|
|
||||||
private boolean monitorEnabled;
|
private boolean monitorEnabled;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
|
||||||
private Timer updateTimer;
|
|
||||||
private StringBuffer updateBuffer;
|
private StringBuffer updateBuffer;
|
||||||
|
private Timer updateTimer;
|
||||||
|
|
||||||
private BoardPort boardPort;
|
private BoardPort boardPort;
|
||||||
|
|
||||||
@ -82,84 +70,10 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
getContentPane().setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
Font consoleFont = Theme.getFont("console.font");
|
onCreateWindow(getContentPane());
|
||||||
Font editorFont = PreferencesData.getFont("editor.font");
|
|
||||||
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
|
|
||||||
|
|
||||||
textArea = new TextAreaFIFO(8000000);
|
this.setMinimumSize(new Dimension(getContentPane().getMinimumSize().width, this.getPreferredSize().height));
|
||||||
textArea.setRows(16);
|
|
||||||
textArea.setColumns(40);
|
|
||||||
textArea.setEditable(false);
|
|
||||||
textArea.setFont(font);
|
|
||||||
|
|
||||||
// don't automatically update the caret. that way we can manually decide
|
|
||||||
// whether or not to do so based on the autoscroll checkbox.
|
|
||||||
((DefaultCaret) textArea.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
|
|
||||||
|
|
||||||
scrollPane = new JScrollPane(textArea);
|
|
||||||
|
|
||||||
getContentPane().add(scrollPane, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
JPanel upperPane = new JPanel();
|
|
||||||
upperPane.setLayout(new BoxLayout(upperPane, BoxLayout.X_AXIS));
|
|
||||||
upperPane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
|
||||||
|
|
||||||
textField = new JTextField(40);
|
|
||||||
sendButton = new JButton(_("Send"));
|
|
||||||
|
|
||||||
upperPane.add(textField);
|
|
||||||
upperPane.add(Box.createRigidArea(new Dimension(4, 0)));
|
|
||||||
upperPane.add(sendButton);
|
|
||||||
|
|
||||||
getContentPane().add(upperPane, BorderLayout.NORTH);
|
|
||||||
|
|
||||||
final JPanel pane = new JPanel();
|
|
||||||
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
|
|
||||||
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
|
||||||
|
|
||||||
autoscrollBox = new JCheckBox(_("Autoscroll"), true);
|
|
||||||
|
|
||||||
noLineEndingAlert = new JLabel(I18n.format(_("You've pressed {0} but nothing was sent. Should you select a line ending?"), _("Send")));
|
|
||||||
noLineEndingAlert.setToolTipText(noLineEndingAlert.getText());
|
|
||||||
noLineEndingAlert.setForeground(pane.getBackground());
|
|
||||||
Dimension minimumSize = new Dimension(noLineEndingAlert.getMinimumSize());
|
|
||||||
minimumSize.setSize(minimumSize.getWidth() / 3, minimumSize.getHeight());
|
|
||||||
noLineEndingAlert.setMinimumSize(minimumSize);
|
|
||||||
|
|
||||||
lineEndings = new JComboBox(new String[]{_("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR")});
|
|
||||||
lineEndings.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent event) {
|
|
||||||
PreferencesData.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
|
|
||||||
noLineEndingAlert.setForeground(pane.getBackground());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (PreferencesData.get("serial.line_ending") != null) {
|
|
||||||
lineEndings.setSelectedIndex(PreferencesData.getInteger("serial.line_ending"));
|
|
||||||
}
|
|
||||||
lineEndings.setMaximumSize(lineEndings.getMinimumSize());
|
|
||||||
|
|
||||||
String[] serialRateStrings = {"300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "74880", "115200", "230400", "250000"};
|
|
||||||
|
|
||||||
serialRates = new JComboBox();
|
|
||||||
for (String rate : serialRateStrings) {
|
|
||||||
serialRates.addItem(rate + " " + _("baud"));
|
|
||||||
}
|
|
||||||
|
|
||||||
serialRates.setMaximumSize(serialRates.getMinimumSize());
|
|
||||||
|
|
||||||
pane.add(autoscrollBox);
|
|
||||||
pane.add(Box.createHorizontalGlue());
|
|
||||||
pane.add(noLineEndingAlert);
|
|
||||||
pane.add(Box.createRigidArea(new Dimension(8, 0)));
|
|
||||||
pane.add(lineEndings);
|
|
||||||
pane.add(Box.createRigidArea(new Dimension(8, 0)));
|
|
||||||
pane.add(serialRates);
|
|
||||||
|
|
||||||
this.setMinimumSize(new Dimension(pane.getMinimumSize().width, this.getPreferredSize().height));
|
|
||||||
|
|
||||||
getContentPane().add(pane, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
pack();
|
pack();
|
||||||
|
|
||||||
@ -186,18 +100,15 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
|||||||
closed = false;
|
closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableWindow(boolean enable) {
|
protected abstract void onCreateWindow(Container mainPane);
|
||||||
textArea.setEnabled(enable);
|
|
||||||
scrollPane.setEnabled(enable);
|
|
||||||
textField.setEnabled(enable);
|
|
||||||
sendButton.setEnabled(enable);
|
|
||||||
autoscrollBox.setEnabled(enable);
|
|
||||||
lineEndings.setEnabled(enable);
|
|
||||||
serialRates.setEnabled(enable);
|
|
||||||
|
|
||||||
|
public void enableWindow(boolean enable) {
|
||||||
|
onEnableWindow(enable);
|
||||||
monitorEnabled = enable;
|
monitorEnabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void onEnableWindow(boolean enable);
|
||||||
|
|
||||||
// Puts the window in suspend state, closing the serial port
|
// Puts the window in suspend state, closing the serial port
|
||||||
// to allow other entity (the programmer) to use it
|
// to allow other entity (the programmer) to use it
|
||||||
public void suspend() throws Exception {
|
public void suspend() throws Exception {
|
||||||
@ -220,15 +131,6 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
|||||||
open();
|
open();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSerialRateChange(ActionListener listener) {
|
|
||||||
serialRates.addActionListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSendCommand(ActionListener listener) {
|
|
||||||
textField.addActionListener(listener);
|
|
||||||
sendButton.addActionListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setPlacement(int[] location) {
|
protected void setPlacement(int[] location) {
|
||||||
setBounds(location[0], location[1], location[2], location[3]);
|
setBounds(location[0], location[1], location[2], location[3]);
|
||||||
}
|
}
|
||||||
@ -246,16 +148,7 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void message(final String s) {
|
public abstract void message(final String s);
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
textArea.append(s);
|
|
||||||
if (autoscrollBox.isSelected()) {
|
|
||||||
textArea.setCaretPosition(textArea.getDocument().getLength());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean requiresAuthorization() {
|
public boolean requiresAuthorization() {
|
||||||
return false;
|
return false;
|
||||||
@ -298,18 +191,10 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener {
|
|||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
String s = consumeUpdateBuffer();
|
String s = consumeUpdateBuffer();
|
||||||
|
|
||||||
if (s.isEmpty()) {
|
if (s.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
//System.out.println("gui append " + s.length());
|
|
||||||
if (autoscrollBox.isSelected()) {
|
|
||||||
textArea.appendTrim(s);
|
|
||||||
textArea.setCaretPosition(textArea.getDocument().getLength());
|
|
||||||
} else {
|
} else {
|
||||||
textArea.appendNoTrim(s);
|
message(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
165
app/src/processing/app/AbstractTextMonitor.java
Normal file
165
app/src/processing/app/AbstractTextMonitor.java
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package processing.app;
|
||||||
|
|
||||||
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.text.DefaultCaret;
|
||||||
|
|
||||||
|
import cc.arduino.packages.BoardPort;
|
||||||
|
import processing.app.debug.TextAreaFIFO;
|
||||||
|
import processing.app.legacy.PApplet;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public abstract class AbstractTextMonitor extends AbstractMonitor {
|
||||||
|
|
||||||
|
protected JLabel noLineEndingAlert;
|
||||||
|
protected TextAreaFIFO textArea;
|
||||||
|
protected JScrollPane scrollPane;
|
||||||
|
protected JTextField textField;
|
||||||
|
protected JButton sendButton;
|
||||||
|
protected JCheckBox autoscrollBox;
|
||||||
|
protected JComboBox lineEndings;
|
||||||
|
protected JComboBox serialRates;
|
||||||
|
|
||||||
|
public AbstractTextMonitor(BoardPort boardPort) {
|
||||||
|
super(boardPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onCreateWindow(Container mainPane) {
|
||||||
|
Font consoleFont = Theme.getFont("console.font");
|
||||||
|
Font editorFont = PreferencesData.getFont("editor.font");
|
||||||
|
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
|
||||||
|
|
||||||
|
mainPane.setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
textArea = new TextAreaFIFO(8000000);
|
||||||
|
textArea.setRows(16);
|
||||||
|
textArea.setColumns(40);
|
||||||
|
textArea.setEditable(false);
|
||||||
|
textArea.setFont(font);
|
||||||
|
|
||||||
|
// don't automatically update the caret. that way we can manually decide
|
||||||
|
// whether or not to do so based on the autoscroll checkbox.
|
||||||
|
((DefaultCaret) textArea.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
|
||||||
|
|
||||||
|
scrollPane = new JScrollPane(textArea);
|
||||||
|
|
||||||
|
mainPane.add(scrollPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel upperPane = new JPanel();
|
||||||
|
upperPane.setLayout(new BoxLayout(upperPane, BoxLayout.X_AXIS));
|
||||||
|
upperPane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||||
|
|
||||||
|
textField = new JTextField(40);
|
||||||
|
sendButton = new JButton(_("Send"));
|
||||||
|
|
||||||
|
upperPane.add(textField);
|
||||||
|
upperPane.add(Box.createRigidArea(new Dimension(4, 0)));
|
||||||
|
upperPane.add(sendButton);
|
||||||
|
|
||||||
|
mainPane.add(upperPane, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
final JPanel pane = new JPanel();
|
||||||
|
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
|
||||||
|
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||||
|
|
||||||
|
autoscrollBox = new JCheckBox(_("Autoscroll"), true);
|
||||||
|
|
||||||
|
noLineEndingAlert = new JLabel(I18n.format(_("You've pressed {0} but nothing was sent. Should you select a line ending?"), _("Send")));
|
||||||
|
noLineEndingAlert.setToolTipText(noLineEndingAlert.getText());
|
||||||
|
noLineEndingAlert.setForeground(pane.getBackground());
|
||||||
|
Dimension minimumSize = new Dimension(noLineEndingAlert.getMinimumSize());
|
||||||
|
minimumSize.setSize(minimumSize.getWidth() / 3, minimumSize.getHeight());
|
||||||
|
noLineEndingAlert.setMinimumSize(minimumSize);
|
||||||
|
|
||||||
|
lineEndings = new JComboBox(new String[]{_("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR")});
|
||||||
|
lineEndings.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
PreferencesData.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
|
||||||
|
noLineEndingAlert.setForeground(pane.getBackground());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (PreferencesData.get("serial.line_ending") != null) {
|
||||||
|
lineEndings.setSelectedIndex(PreferencesData.getInteger("serial.line_ending"));
|
||||||
|
}
|
||||||
|
lineEndings.setMaximumSize(lineEndings.getMinimumSize());
|
||||||
|
|
||||||
|
String[] serialRateStrings = {
|
||||||
|
"300", "1200", "2400", "4800", "9600",
|
||||||
|
"19200", "38400", "57600", "115200", "230400", "250000"
|
||||||
|
};
|
||||||
|
|
||||||
|
serialRates = new JComboBox();
|
||||||
|
for (String rate : serialRateStrings) {
|
||||||
|
serialRates.addItem(rate + " " + _("baud"));
|
||||||
|
}
|
||||||
|
|
||||||
|
serialRates.setMaximumSize(serialRates.getMinimumSize());
|
||||||
|
|
||||||
|
pane.add(autoscrollBox);
|
||||||
|
pane.add(Box.createHorizontalGlue());
|
||||||
|
pane.add(noLineEndingAlert);
|
||||||
|
pane.add(Box.createRigidArea(new Dimension(8, 0)));
|
||||||
|
pane.add(lineEndings);
|
||||||
|
pane.add(Box.createRigidArea(new Dimension(8, 0)));
|
||||||
|
pane.add(serialRates);
|
||||||
|
|
||||||
|
mainPane.add(pane, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onEnableWindow(boolean enable)
|
||||||
|
{
|
||||||
|
textArea.setEnabled(enable);
|
||||||
|
scrollPane.setEnabled(enable);
|
||||||
|
textField.setEnabled(enable);
|
||||||
|
sendButton.setEnabled(enable);
|
||||||
|
autoscrollBox.setEnabled(enable);
|
||||||
|
lineEndings.setEnabled(enable);
|
||||||
|
serialRates.setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSendCommand(ActionListener listener) {
|
||||||
|
textField.addActionListener(listener);
|
||||||
|
sendButton.addActionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSerialRateChange(ActionListener listener) {
|
||||||
|
serialRates.addActionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void message(final String s) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
textArea.append(s);
|
||||||
|
if (autoscrollBox.isSelected()) {
|
||||||
|
textArea.setCaretPosition(textArea.getDocument().getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -138,6 +138,7 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
private static JMenu portMenu;
|
private static JMenu portMenu;
|
||||||
|
|
||||||
static volatile AbstractMonitor serialMonitor;
|
static volatile AbstractMonitor serialMonitor;
|
||||||
|
static AbstractMonitor serialPlotter;
|
||||||
|
|
||||||
final EditorHeader header;
|
final EditorHeader header;
|
||||||
EditorStatus status;
|
EditorStatus status;
|
||||||
@ -787,6 +788,14 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
item.addActionListener(e -> handleSerial());
|
item.addActionListener(e -> handleSerial());
|
||||||
toolsMenu.add(item);
|
toolsMenu.add(item);
|
||||||
|
|
||||||
|
item = newJMenuItemShift(_("Serial Plotter"), 'L');
|
||||||
|
item.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
handlePlotter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toolsMenu.add(item);
|
||||||
|
|
||||||
addTools(toolsMenu, BaseNoGui.getToolsFolder());
|
addTools(toolsMenu, BaseNoGui.getToolsFolder());
|
||||||
File sketchbookTools = new File(BaseNoGui.getSketchbookFolder(), "tools");
|
File sketchbookTools = new File(BaseNoGui.getSketchbookFolder(), "tools");
|
||||||
addTools(toolsMenu, sketchbookTools);
|
addTools(toolsMenu, sketchbookTools);
|
||||||
@ -1113,6 +1122,7 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
}
|
}
|
||||||
if (selection != null) selection.setState(true);
|
if (selection != null) selection.setState(true);
|
||||||
//System.out.println(item.getLabel());
|
//System.out.println(item.getLabel());
|
||||||
|
|
||||||
BaseNoGui.selectSerialPort(name);
|
BaseNoGui.selectSerialPort(name);
|
||||||
if (serialMonitor != null) {
|
if (serialMonitor != null) {
|
||||||
try {
|
try {
|
||||||
@ -1123,6 +1133,16 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serialPlotter != null) {
|
||||||
|
try {
|
||||||
|
serialPlotter.close();
|
||||||
|
serialPlotter.setVisible(false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBoardOrPortChange();
|
||||||
base.onBoardOrPortChange();
|
base.onBoardOrPortChange();
|
||||||
|
|
||||||
//System.out.println("set to " + get("serial.port"));
|
//System.out.println("set to " + get("serial.port"));
|
||||||
@ -2389,6 +2409,9 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
if (serialMonitor != null) {
|
if (serialMonitor != null) {
|
||||||
serialMonitor.suspend();
|
serialMonitor.suspend();
|
||||||
}
|
}
|
||||||
|
if (serialPlotter != null) {
|
||||||
|
serialPlotter.suspend();
|
||||||
|
}
|
||||||
|
|
||||||
uploading = true;
|
uploading = true;
|
||||||
|
|
||||||
@ -2420,6 +2443,7 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
toolbar.deactivate(EditorToolbar.EXPORT);
|
toolbar.deactivate(EditorToolbar.EXPORT);
|
||||||
|
|
||||||
resumeOrCloseSerialMonitor();
|
resumeOrCloseSerialMonitor();
|
||||||
|
resumeOrCloseSerialPlotter();
|
||||||
base.onBoardOrPortChange();
|
base.onBoardOrPortChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2439,6 +2463,8 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
if (serialMonitor != null)
|
||||||
|
serialMonitor.resume(boardPort);
|
||||||
if (boardPort == null) {
|
if (boardPort == null) {
|
||||||
serialMonitor.close();
|
serialMonitor.close();
|
||||||
handleSerial();
|
handleSerial();
|
||||||
@ -2448,7 +2474,26 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
statusError(e);
|
statusError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resumeOrCloseSerialPlotter() {
|
||||||
|
// Return the serial plotter window to its initial state
|
||||||
|
if (serialPlotter != null) {
|
||||||
|
BoardPort boardPort = BaseNoGui.getDiscoveryManager().find(PreferencesData.get("serial.port"));
|
||||||
|
try {
|
||||||
|
if (serialPlotter != null)
|
||||||
|
serialPlotter.resume(boardPort);
|
||||||
|
if (boardPort == null) {
|
||||||
|
serialPlotter.close();
|
||||||
|
handlePlotter();
|
||||||
|
} else {
|
||||||
|
serialPlotter.resume(boardPort);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
statusError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DAM: in Arduino, this is upload (with verbose output)
|
// DAM: in Arduino, this is upload (with verbose output)
|
||||||
@ -2459,6 +2504,9 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
if (serialMonitor != null) {
|
if (serialMonitor != null) {
|
||||||
serialMonitor.suspend();
|
serialMonitor.suspend();
|
||||||
}
|
}
|
||||||
|
if (serialPlotter != null) {
|
||||||
|
serialPlotter.suspend();
|
||||||
|
}
|
||||||
|
|
||||||
uploading = true;
|
uploading = true;
|
||||||
|
|
||||||
@ -2490,12 +2538,23 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
toolbar.deactivate(EditorToolbar.EXPORT);
|
toolbar.deactivate(EditorToolbar.EXPORT);
|
||||||
|
|
||||||
resumeOrCloseSerialMonitor();
|
resumeOrCloseSerialMonitor();
|
||||||
|
resumeOrCloseSerialPlotter();
|
||||||
|
|
||||||
base.onBoardOrPortChange();
|
base.onBoardOrPortChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void handleSerial() {
|
public void handleSerial() {
|
||||||
|
if(serialPlotter != null) {
|
||||||
|
if(serialPlotter.isClosed()) {
|
||||||
|
serialPlotter = null;
|
||||||
|
} else {
|
||||||
|
statusError(I18n.format("Serial monitor not available while plotter is open"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (serialMonitor != null) {
|
if (serialMonitor != null) {
|
||||||
// The serial monitor already exists
|
// The serial monitor already exists
|
||||||
|
|
||||||
@ -2583,6 +2642,96 @@ public class Editor extends JFrame implements RunnerListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handlePlotter() {
|
||||||
|
if(serialMonitor != null) {
|
||||||
|
if(serialMonitor.isClosed()) {
|
||||||
|
serialMonitor = null;
|
||||||
|
} else {
|
||||||
|
statusError(I18n.format("Plotter not available while serial monitor is open"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serialPlotter != null) {
|
||||||
|
// The serial plotter already exists
|
||||||
|
|
||||||
|
if (serialPlotter.isClosed()) {
|
||||||
|
// If it's closed, clear the refrence to the existing
|
||||||
|
// plotter and create a new one
|
||||||
|
serialPlotter = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If it's not closed, give it the focus
|
||||||
|
try {
|
||||||
|
serialPlotter.toFront();
|
||||||
|
serialPlotter.requestFocus();
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoardPort port = Base.getDiscoveryManager().find(PreferencesData.get("serial.port"));
|
||||||
|
|
||||||
|
if (port == null) {
|
||||||
|
statusError(I18n.format("Board at {0} is not available", PreferencesData.get("serial.port")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialPlotter = new SerialPlotter(port);
|
||||||
|
serialPlotter.setIconImage(getIconImage());
|
||||||
|
|
||||||
|
// If currently uploading, disable the plotter (it will be later
|
||||||
|
// enabled when done uploading)
|
||||||
|
if (uploading) {
|
||||||
|
try {
|
||||||
|
serialPlotter.suspend();
|
||||||
|
} catch (Exception e) {
|
||||||
|
statusError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
do {
|
||||||
|
if (serialPlotter.requiresAuthorization() && !PreferencesData.has(serialPlotter.getAuthorizationKey())) {
|
||||||
|
PasswordAuthorizationDialog dialog = new PasswordAuthorizationDialog(this, _("Type board password to access its console"));
|
||||||
|
dialog.setLocationRelativeTo(this);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
|
||||||
|
if (dialog.isCancelled()) {
|
||||||
|
statusNotice(_("Unable to open serial plotter"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferencesData.set(serialPlotter.getAuthorizationKey(), dialog.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
serialPlotter.open();
|
||||||
|
serialPlotter.setVisible(true);
|
||||||
|
success = true;
|
||||||
|
} catch (ConnectException e) {
|
||||||
|
statusError(_("Unable to connect: is the sketch using the bridge?"));
|
||||||
|
} catch (JSchException e) {
|
||||||
|
statusError(_("Unable to connect: wrong password?"));
|
||||||
|
} catch (SerialException e) {
|
||||||
|
String errorMessage = e.getMessage();
|
||||||
|
if (e.getCause() != null && e.getCause() instanceof SerialPortException) {
|
||||||
|
errorMessage += " (" + ((SerialPortException) e.getCause()).getExceptionType() + ")";
|
||||||
|
}
|
||||||
|
statusError(errorMessage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
statusError(e);
|
||||||
|
} finally {
|
||||||
|
if (serialPlotter.requiresAuthorization() && !success) {
|
||||||
|
PreferencesData.remove(serialPlotter.getAuthorizationKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (serialPlotter.requiresAuthorization() && !success);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void handleBurnBootloader() {
|
private void handleBurnBootloader() {
|
||||||
console.clear();
|
console.clear();
|
||||||
|
@ -38,12 +38,12 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
|
|
||||||
/** Rollover titles for each button. */
|
/** Rollover titles for each button. */
|
||||||
static final String title[] = {
|
static final String title[] = {
|
||||||
_("Verify"), _("Upload"), _("New"), _("Open"), _("Save"), _("Serial Monitor")
|
_("Verify"), _("Upload"), _("New"), _("Open"), _("Save"), _("Serial Monitor"), _("Serial Plotter")
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Titles for each button when the shift key is pressed. */
|
/** Titles for each button when the shift key is pressed. */
|
||||||
static final String titleShift[] = {
|
static final String titleShift[] = {
|
||||||
_("Verify"), _("Upload Using Programmer"), _("New"), _("Open in Another Window"), _("Save As..."), _("Serial Monitor")
|
_("Verify"), _("Upload Using Programmer"), _("New"), _("Open in Another Window"), _("Save As..."), _("Serial Monitor"), _("Serial Plotter")
|
||||||
};
|
};
|
||||||
|
|
||||||
static final int BUTTON_COUNT = title.length;
|
static final int BUTTON_COUNT = title.length;
|
||||||
@ -65,6 +65,7 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
static final int SAVE = 4;
|
static final int SAVE = 4;
|
||||||
|
|
||||||
static final int SERIAL = 5;
|
static final int SERIAL = 5;
|
||||||
|
static final int PLOTTER = 6;
|
||||||
|
|
||||||
static final int INACTIVE = 0;
|
static final int INACTIVE = 0;
|
||||||
static final int ROLLOVER = 1;
|
static final int ROLLOVER = 1;
|
||||||
@ -110,6 +111,7 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
which[buttonCount++] = OPEN;
|
which[buttonCount++] = OPEN;
|
||||||
which[buttonCount++] = SAVE;
|
which[buttonCount++] = SAVE;
|
||||||
which[buttonCount++] = SERIAL;
|
which[buttonCount++] = SERIAL;
|
||||||
|
which[buttonCount++] = PLOTTER;
|
||||||
|
|
||||||
currentRollover = -1;
|
currentRollover = -1;
|
||||||
|
|
||||||
@ -173,8 +175,11 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Serial button must be on the right
|
// Serial button must be on the right
|
||||||
x1[SERIAL] = width - BUTTON_WIDTH - 14;
|
x1[SERIAL] = width - 2 * BUTTON_WIDTH - 14;
|
||||||
x2[SERIAL] = width - 14;
|
x2[SERIAL] = width - BUTTON_WIDTH - 14;
|
||||||
|
// Plotter button too
|
||||||
|
x1[PLOTTER] = width - BUTTON_WIDTH - 14;
|
||||||
|
x2[PLOTTER] = width - 14;
|
||||||
}
|
}
|
||||||
Graphics g = offscreen.getGraphics();
|
Graphics g = offscreen.getGraphics();
|
||||||
g.setColor(bgcolor); //getBackground());
|
g.setColor(bgcolor); //getBackground());
|
||||||
@ -201,12 +206,15 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
if (currentRollover != -1) {
|
if (currentRollover != -1) {
|
||||||
int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
|
int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
|
||||||
String status = shiftPressed ? titleShift[currentRollover] : title[currentRollover];
|
String status = shiftPressed ? titleShift[currentRollover] : title[currentRollover];
|
||||||
if (currentRollover != SERIAL)
|
switch (currentRollover) {
|
||||||
g.drawString(status, (buttonCount-1) * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY);
|
case SERIAL:
|
||||||
else {
|
case PLOTTER:
|
||||||
int statusX = x1[SERIAL] - BUTTON_GAP;
|
int statusX = x1[SERIAL] - BUTTON_GAP;
|
||||||
statusX -= g.getFontMetrics().stringWidth(status);
|
statusX -= g.getFontMetrics().stringWidth(status);
|
||||||
g.drawString(status, statusX, statusY);
|
g.drawString(status, statusX, statusY);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g.drawString(status, (buttonCount-1) * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +364,10 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key
|
|||||||
case SERIAL:
|
case SERIAL:
|
||||||
editor.handleSerial();
|
editor.handleSerial();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PLOTTER:
|
||||||
|
editor.handlePlotter();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import java.io.OutputStream;
|
|||||||
import static processing.app.I18n._;
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class NetworkMonitor extends AbstractMonitor implements MessageConsumer {
|
public class NetworkMonitor extends AbstractTextMonitor implements MessageConsumer {
|
||||||
|
|
||||||
private static final int MAX_CONNECTION_ATTEMPTS = 5;
|
private static final int MAX_CONNECTION_ATTEMPTS = 5;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import java.awt.event.ActionListener;
|
|||||||
import static processing.app.I18n._;
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class SerialMonitor extends AbstractMonitor {
|
public class SerialMonitor extends AbstractTextMonitor {
|
||||||
|
|
||||||
private Serial serial;
|
private Serial serial;
|
||||||
private int serialRate;
|
private int serialRate;
|
||||||
|
242
app/src/processing/app/SerialPlotter.java
Normal file
242
app/src/processing/app/SerialPlotter.java
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
package processing.app;
|
||||||
|
|
||||||
|
import cc.arduino.packages.BoardPort;
|
||||||
|
import processing.app.legacy.PApplet;
|
||||||
|
|
||||||
|
import processing.app.debug.MessageConsumer;
|
||||||
|
import processing.app.helpers.*;
|
||||||
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.awt.geom.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.*;
|
||||||
|
import javax.swing.event.*;
|
||||||
|
import javax.swing.text.*;
|
||||||
|
|
||||||
|
public class SerialPlotter extends AbstractMonitor {
|
||||||
|
private StringBuffer messageBuffer;
|
||||||
|
private CircularBuffer buffer;
|
||||||
|
private GraphPanel graphPanel;
|
||||||
|
private JComboBox serialRates;
|
||||||
|
|
||||||
|
private Serial serial;
|
||||||
|
private int serialRate;
|
||||||
|
|
||||||
|
private class GraphPanel extends JPanel {
|
||||||
|
private double minY, maxY, rangeY;
|
||||||
|
private Rectangle bounds;
|
||||||
|
private int xOffset;
|
||||||
|
private Font font;
|
||||||
|
private Color graphColor;
|
||||||
|
|
||||||
|
public GraphPanel() {
|
||||||
|
font = Theme.getFont("console.font");
|
||||||
|
graphColor = Theme.getColor("header.bgcolor");
|
||||||
|
xOffset = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintComponent(Graphics g1) {
|
||||||
|
Graphics2D g = (Graphics2D)g1;
|
||||||
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
g.setFont(font);
|
||||||
|
super.paintComponent(g);
|
||||||
|
|
||||||
|
bounds = g.getClipBounds();
|
||||||
|
setBackground(Color.WHITE);
|
||||||
|
if(buffer.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
minY = buffer.min();
|
||||||
|
maxY = buffer.max();
|
||||||
|
Ticks ticks = new Ticks(minY, maxY, 3);
|
||||||
|
minY = Math.min(minY, ticks.getTick(0));
|
||||||
|
maxY = Math.max(maxY, ticks.getTick(ticks.getTickCount() - 1));
|
||||||
|
rangeY = maxY - minY;
|
||||||
|
minY -= 0.05 * rangeY;
|
||||||
|
maxY += 0.05 * rangeY;
|
||||||
|
rangeY = maxY - minY;
|
||||||
|
|
||||||
|
g.setStroke(new BasicStroke(1.0f));
|
||||||
|
FontMetrics fm = g.getFontMetrics();
|
||||||
|
for(int i = 0; i < ticks.getTickCount(); ++i) {
|
||||||
|
double tick = ticks.getTick(i);
|
||||||
|
Rectangle2D fRect = fm.getStringBounds(String.valueOf(tick), g);
|
||||||
|
xOffset = Math.max(xOffset, (int)fRect.getWidth() + 15);
|
||||||
|
|
||||||
|
// draw tick
|
||||||
|
g.drawLine(xOffset - 5, (int)transformY(tick), xOffset + 2, (int)transformY(tick));
|
||||||
|
// draw tick label
|
||||||
|
g.drawString(String.valueOf(tick), xOffset - (int)fRect.getWidth() - 10, transformY(tick) - (float)fRect.getHeight() * 0.5f + fm.getAscent());
|
||||||
|
}
|
||||||
|
|
||||||
|
g.drawLine(bounds.x + xOffset, bounds.y + 5, bounds.x + xOffset, bounds.y + bounds.height - 10);
|
||||||
|
|
||||||
|
g.setTransform(AffineTransform.getTranslateInstance(xOffset, 0));
|
||||||
|
float xstep = (float)(bounds.width - xOffset) / (float)buffer.capacity();
|
||||||
|
|
||||||
|
g.setColor(graphColor);
|
||||||
|
g.setStroke(new BasicStroke(0.75f));
|
||||||
|
|
||||||
|
for(int i = 0; i < buffer.size() - 1; ++i) {
|
||||||
|
g.drawLine(
|
||||||
|
(int)(i * xstep), (int)transformY(buffer.get(i)),
|
||||||
|
(int)((i + 1) * xstep), (int)transformY(buffer.get(i + 1))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getMinimumSize() {
|
||||||
|
return new Dimension(200, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension(500, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float transformY(double rawY) {
|
||||||
|
return (float)(5 + (bounds.height - 10) * (1.0 - (rawY - minY) / rangeY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerialPlotter(BoardPort port) {
|
||||||
|
super(port);
|
||||||
|
|
||||||
|
serialRate = PreferencesData.getInteger("serial.debug_rate");
|
||||||
|
serialRates.setSelectedItem(serialRate + " " + _("baud"));
|
||||||
|
onSerialRateChange(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
String wholeString = (String) serialRates.getSelectedItem();
|
||||||
|
String rateString = wholeString.substring(0, wholeString.indexOf(' '));
|
||||||
|
serialRate = Integer.parseInt(rateString);
|
||||||
|
PreferencesData.set("serial.debug_rate", rateString);
|
||||||
|
try {
|
||||||
|
close();
|
||||||
|
Thread.sleep(100); // Wait for serial port to properly close
|
||||||
|
open();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// noop
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
messageBuffer = new StringBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onCreateWindow(Container mainPane) {
|
||||||
|
mainPane.setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
Font consoleFont = Theme.getFont("console.font");
|
||||||
|
Font editorFont = PreferencesData.getFont("editor.font");
|
||||||
|
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
|
||||||
|
|
||||||
|
buffer = new CircularBuffer(500);
|
||||||
|
graphPanel = new GraphPanel();
|
||||||
|
|
||||||
|
mainPane.add(graphPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel pane = new JPanel();
|
||||||
|
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
|
||||||
|
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||||
|
|
||||||
|
String[] serialRateStrings = {
|
||||||
|
"300","1200","2400","4800","9600","14400",
|
||||||
|
"19200","28800","38400","57600","115200"
|
||||||
|
};
|
||||||
|
|
||||||
|
serialRates = new JComboBox();
|
||||||
|
for (int i = 0; i < serialRateStrings.length; i++)
|
||||||
|
serialRates.addItem(serialRateStrings[i] + " " + _("baud"));
|
||||||
|
|
||||||
|
serialRates.setMaximumSize(serialRates.getMinimumSize());
|
||||||
|
|
||||||
|
pane.add(Box.createRigidArea(new Dimension(8, 0)));
|
||||||
|
pane.add(serialRates);
|
||||||
|
|
||||||
|
mainPane.add(pane, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onEnableWindow(boolean enable)
|
||||||
|
{
|
||||||
|
serialRates.setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSerialRateChange(ActionListener listener) {
|
||||||
|
serialRates.addActionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void message(final String s) {
|
||||||
|
messageBuffer.append(s);
|
||||||
|
while(true) {
|
||||||
|
int linebreak = messageBuffer.indexOf("\n");
|
||||||
|
if(linebreak == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String line = messageBuffer.substring(0, linebreak);
|
||||||
|
line = line.trim();
|
||||||
|
messageBuffer.delete(0, linebreak + 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
double value = Double.valueOf(line);
|
||||||
|
buffer.add(value);
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
continue; // ignore lines that can't be cast to a number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
SerialPlotter.this.repaint();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open() throws Exception {
|
||||||
|
super.open();
|
||||||
|
|
||||||
|
if (serial != null) return;
|
||||||
|
|
||||||
|
serial = new Serial(getBoardPort().getAddress(), serialRate) {
|
||||||
|
@Override
|
||||||
|
protected void message(char buff[], int n) {
|
||||||
|
addToUpdateBuffer(buff, n);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws Exception {
|
||||||
|
if (serial != null) {
|
||||||
|
super.close();
|
||||||
|
int[] location = getPlacement();
|
||||||
|
String locationStr = PApplet.join(PApplet.str(location), ",");
|
||||||
|
PreferencesData.set("last.serial.location", locationStr);
|
||||||
|
serial.dispose();
|
||||||
|
serial = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
app/src/processing/app/helpers/CircularBuffer.java
Normal file
81
app/src/processing/app/helpers/CircularBuffer.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package processing.app.helpers;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class CircularBuffer {
|
||||||
|
private double[] elements;
|
||||||
|
private int start = -1;
|
||||||
|
private int end = -1;
|
||||||
|
private int capacity;
|
||||||
|
|
||||||
|
public void add(double num) {
|
||||||
|
end = (end + 1) % capacity;
|
||||||
|
elements[end] = num;
|
||||||
|
if(start == end || start == -1) {
|
||||||
|
start = (start + 1) % capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double get(int index) {
|
||||||
|
if(index >= capacity) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
if(index >= size()) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements[(start + index) % capacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return start == -1 && end == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
start = end = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CircularBuffer(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
elements = new double[capacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
public double min() {
|
||||||
|
if(size() == 0) {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
double out = get(0);
|
||||||
|
for(int i = 1; i < size(); ++i) {
|
||||||
|
out = Math.min(out, get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double max() {
|
||||||
|
if(size() == 0) {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
double out = get(0);
|
||||||
|
for(int i = 1; i < size(); ++i) {
|
||||||
|
out = Math.max(out, get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
if(end == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (end - start + capacity) % capacity + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int capacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
46
app/src/processing/app/helpers/Ticks.java
Normal file
46
app/src/processing/app/helpers/Ticks.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package processing.app.helpers;
|
||||||
|
|
||||||
|
public class Ticks {
|
||||||
|
private double tickMin;
|
||||||
|
private double tickMax;
|
||||||
|
private double tickStep;
|
||||||
|
private int tickCount;
|
||||||
|
|
||||||
|
private double[] ticks;
|
||||||
|
|
||||||
|
public Ticks(double min, double max, int tickCount) {
|
||||||
|
double range = max - min;
|
||||||
|
double exp = Math.floor(Math.log10(range / (tickCount - 1)));
|
||||||
|
double scale = Math.pow(10, exp);
|
||||||
|
|
||||||
|
double rawTickStep = (range / (tickCount - 1)) / scale;
|
||||||
|
for(double potentialStep : new double[] {1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0}) {
|
||||||
|
if(potentialStep < rawTickStep) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tickStep = potentialStep * scale;
|
||||||
|
tickMin = tickStep * Math.floor(min / tickStep);
|
||||||
|
tickMax = tickMin + tickStep * (tickCount - 1);
|
||||||
|
if(tickMax >= max) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tickCount -= (int)Math.floor((tickMax - max) / tickStep);
|
||||||
|
this.tickCount = tickCount;
|
||||||
|
|
||||||
|
ticks = new double[tickCount];
|
||||||
|
for(int i = 0; i < tickCount; ++i) {
|
||||||
|
ticks[i] = tickMin + i * tickStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTick(int i) {
|
||||||
|
return ticks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTickCount() {
|
||||||
|
return tickCount;
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.7 KiB |
Loading…
x
Reference in New Issue
Block a user