1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-03-15 12:29:26 +01:00

Serial.dispose() throws IOException

SerialException extends IOException
SerialMonitor is now a subclass of a generic AbstractMonitor; introducing NetworkMonitor
UploaderFactory becomes PerPortObjectFactory and can build AbstractMonitors
favouring IOException over SerialException
collecting constants in Constants
made MessageSiphon stoppable
This commit is contained in:
Federico Fissore 2013-05-29 16:14:17 +02:00
parent 556c6ea5c1
commit 376b0f8b3f
16 changed files with 396 additions and 241 deletions

View File

@ -0,0 +1,183 @@
package processing.app;
import processing.app.debug.MessageConsumer;
import processing.core.PApplet;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.text.DefaultCaret;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import static processing.app.I18n._;
public abstract class AbstractMonitor extends JFrame implements MessageConsumer {
protected JTextArea textArea;
protected JScrollPane scrollPane;
protected JTextField textField;
protected JButton sendButton;
protected JCheckBox autoscrollBox;
protected JComboBox lineEndings;
protected JComboBox serialRates;
protected int serialRate;
public AbstractMonitor(String title) {
super(title);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
try {
close();
} catch (IOException e) {
// ignore
}
}
});
// obvious, no?
KeyStroke wc = Editor.WINDOW_CLOSE_KEYSTROKE;
getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(wc, "close");
getRootPane().getActionMap().put("close", (new AbstractAction() {
public void actionPerformed(ActionEvent event) {
try {
close();
} catch (IOException e) {
// ignore
}
setVisible(false);
}
}));
getContentPane().setLayout(new BorderLayout());
Font consoleFont = Theme.getFont("console.font");
Font editorFont = Preferences.getFont("editor.font");
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
textArea = new JTextArea(16, 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 pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
textField = new JTextField(40);
sendButton = new JButton(_("Send"));
pane.add(textField);
pane.add(Box.createRigidArea(new Dimension(4, 0)));
pane.add(sendButton);
getContentPane().add(pane, BorderLayout.NORTH);
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
autoscrollBox = new JCheckBox(_("Autoscroll"), true);
lineEndings = new JComboBox(new String[]{_("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR")});
lineEndings.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
Preferences.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
}
});
if (Preferences.get("serial.line_ending") != null) {
lineEndings.setSelectedIndex(Preferences.getInteger("serial.line_ending"));
}
lineEndings.setMaximumSize(lineEndings.getMinimumSize());
String[] serialRateStrings = {
"300", "1200", "2400", "4800", "9600",
"19200", "57600", "115200"
};
serialRates = new JComboBox();
for (int i = 0; i < serialRateStrings.length; i++)
serialRates.addItem(serialRateStrings[i] + " " + _("baud"));
serialRate = Preferences.getInteger("serial.debug_rate");
serialRates.setSelectedItem(serialRate + " " + _("baud"));
serialRates.setMaximumSize(serialRates.getMinimumSize());
pane.add(autoscrollBox);
pane.add(Box.createHorizontalGlue());
pane.add(lineEndings);
pane.add(Box.createRigidArea(new Dimension(8, 0)));
pane.add(serialRates);
getContentPane().add(pane, BorderLayout.SOUTH);
pack();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
if (Preferences.get("last.screen.height") != null) {
// if screen size has changed, the window coordinates no longer
// make sense, so don't use them unless they're identical
int screenW = Preferences.getInteger("last.screen.width");
int screenH = Preferences.getInteger("last.screen.height");
if ((screen.width == screenW) && (screen.height == screenH)) {
String locationStr = Preferences.get("last.serial.location");
if (locationStr != null) {
int[] location = PApplet.parseInt(PApplet.split(locationStr, ','));
setPlacement(location);
}
}
}
}
public void onSerialRateChange(ActionListener listener) {
serialRates.addActionListener(listener);
}
public void onSendCommand(ActionListener listener) {
textField.addActionListener(listener);
sendButton.addActionListener(listener);
}
protected void setPlacement(int[] location) {
setBounds(location[0], location[1], location[2], location[3]);
}
protected int[] getPlacement() {
int[] location = new int[4];
// Get the dimensions of the Frame
Rectangle bounds = getBounds();
location[0] = bounds.x;
location[1] = bounds.y;
location[2] = bounds.width;
location[3] = bounds.height;
return location;
}
public void message(final String s) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(s);
if (autoscrollBox.isSelected()) {
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
});
}
public abstract void open() throws IOException;
public abstract void close() throws IOException;
}

View File

@ -936,7 +936,11 @@ public class Base {
// This will store the sketch count as zero // This will store the sketch count as zero
editors.remove(editor); editors.remove(editor);
Editor.serialMonitor.closeSerialPort(); try {
Editor.serialMonitor.close();
} catch (IOException e) {
//ignore
}
storeSketches(); storeSketches();
// Save out the current prefs state // Save out the current prefs state
@ -974,7 +978,11 @@ public class Base {
// If quit is canceled, this will be replaced anyway // If quit is canceled, this will be replaced anyway
// by a later handleQuit() that is not canceled. // by a later handleQuit() that is not canceled.
storeSketches(); storeSketches();
Editor.serialMonitor.closeSerialPort(); try {
Editor.serialMonitor.close();
} catch (IOException e) {
// ignore
}
if (handleQuitEach()) { if (handleQuitEach()) {
// make sure running sketches close before quitting // make sure running sketches close before quitting

View File

@ -0,0 +1,9 @@
package processing.app;
import java.util.regex.Pattern;
public class Constants {
public static final Pattern IPV4_ADDRESS = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
}

View File

@ -99,7 +99,7 @@ public class Editor extends JFrame implements RunnerListener {
static List<JMenu> boardsMenus; static List<JMenu> boardsMenus;
static JMenu serialMenu; static JMenu serialMenu;
static SerialMonitor serialMonitor; static AbstractMonitor serialMonitor;
EditorHeader header; EditorHeader header;
EditorStatus status; EditorStatus status;
@ -204,7 +204,7 @@ public class Editor extends JFrame implements RunnerListener {
//sketchbook = new Sketchbook(this); //sketchbook = new Sketchbook(this);
if (serialMonitor == null) { if (serialMonitor == null) {
serialMonitor = new SerialMonitor(Preferences.get("serial.port")); serialMonitor = new PerPortObjectFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor.setIconImage(getIconImage()); serialMonitor.setIconImage(getIconImage());
} }
@ -964,9 +964,13 @@ public class Editor extends JFrame implements RunnerListener {
Preferences.set("serial.port.file", name.substring(5)); Preferences.set("serial.port.file", name.substring(5));
else else
Preferences.set("serial.port.file", name); Preferences.set("serial.port.file", name);
serialMonitor.closeSerialPort(); try {
serialMonitor.close();
} catch (IOException e) {
// ignore
}
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
serialMonitor = new SerialMonitor(Preferences.get("serial.port")); serialMonitor = new PerPortObjectFactory().newMonitor(Preferences.get("serial.port"), base);
onBoardOrPortChange(); onBoardOrPortChange();
@ -2401,7 +2405,7 @@ public class Editor extends JFrame implements RunnerListener {
public void run() { public void run() {
try { try {
serialMonitor.closeSerialPort(); serialMonitor.close();
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
uploading = true; uploading = true;
@ -2437,7 +2441,7 @@ public class Editor extends JFrame implements RunnerListener {
public void run() { public void run() {
try { try {
serialMonitor.closeSerialPort(); serialMonitor.close();
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
uploading = true; uploading = true;
@ -2507,9 +2511,11 @@ public class Editor extends JFrame implements RunnerListener {
if (uploading) return; if (uploading) return;
try { try {
serialMonitor.openSerialPort(); serialMonitor.open();
serialMonitor.setVisible(true); serialMonitor.setVisible(true);
} catch (SerialException e) { } catch (ConnectException e) {
statusError(_("Unable to connect: is the sketch using the bridge?"));
} catch (IOException e) {
statusError(e); statusError(e);
} }
} }

View File

@ -0,0 +1,73 @@
package processing.app;
import processing.app.debug.MessageSiphon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.regex.Matcher;
public class NetworkMonitor extends AbstractMonitor {
private static final int MAX_CONNECT_RETRIES = 3;
private final String ipAddress;
private final Base base;
private Socket socket;
private MessageSiphon consumer;
public NetworkMonitor(String port, Base base) {
super(port);
this.base = base;
Matcher matcher = Constants.IPV4_ADDRESS.matcher(port);
matcher.find();
this.ipAddress = matcher.group();
onSendCommand(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
socket.getOutputStream().write(textField.getText().getBytes());
socket.getOutputStream().write('\n');
socket.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
textField.setText("");
}
});
}
@Override
public void open() throws IOException {
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 6571), 5000);
consumer = new MessageSiphon(socket.getInputStream(), this);
return;
} catch (IOException e) {
socket = null;
throw e;
}
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// ignore
}
}
@Override
public void close() throws IOException {
if (socket != null) {
consumer.stop();
socket.close();
textArea.setText("");
}
}
}

View File

@ -0,0 +1,28 @@
package processing.app;
import processing.app.debug.BasicUploader;
import processing.app.debug.HttpUploader;
import processing.app.debug.TargetBoard;
import processing.app.debug.Uploader;
import java.util.regex.Pattern;
public class PerPortObjectFactory {
public Uploader newUploader(TargetBoard board, String port) {
if ("true".equals(board.getPreferences().get("upload.via_http")) && Constants.IPV4_ADDRESS.matcher(port).find()) {
return new HttpUploader(port);
}
return new BasicUploader();
}
public AbstractMonitor newMonitor(String port, Base base) {
if (Constants.IPV4_ADDRESS.matcher(port).find()) {
return new NetworkMonitor(port, base);
}
return new SerialMonitor(port);
}
}

View File

@ -219,24 +219,15 @@ public class Serial implements SerialPortEventListener {
//public void key(java.awt.event.KeyEvent e) { } //public void key(java.awt.event.KeyEvent e) { }
public void dispose() { public void dispose() throws IOException {
try {
// do io streams need to be closed first? // do io streams need to be closed first?
if (input != null) input.close(); if (input != null) input.close();
if (output != null) output.close(); if (output != null) output.close();
} catch (Exception e) {
e.printStackTrace();
}
input = null; input = null;
output = null; output = null;
try {
if (port != null) port.close(); // close the port if (port != null) port.close(); // close the port
} catch (Exception e) {
e.printStackTrace();
}
port = null; port = null;
} }

View File

@ -20,7 +20,9 @@
package processing.app; package processing.app;
public class SerialException extends Exception { import java.io.IOException;
public class SerialException extends IOException {
public SerialException() { public SerialException() {
super(); super();
} }

View File

@ -18,27 +18,16 @@
package processing.app; package processing.app;
import processing.app.debug.MessageConsumer; import processing.core.PApplet;
import processing.core.*;
import static processing.app.I18n._;
import java.awt.*; import java.awt.event.ActionEvent;
import java.awt.event.*; import java.awt.event.ActionListener;
import javax.swing.*; import java.io.IOException;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class SerialMonitor extends JFrame implements MessageConsumer { public class SerialMonitor extends AbstractMonitor {
private final String port;
private Serial serial; private Serial serial;
private String port;
private JTextArea textArea;
private JScrollPane scrollPane;
private JTextField textField;
private JButton sendButton;
private JCheckBox autoscrollBox;
private JComboBox lineEndings;
private JComboBox serialRates;
private int serialRate; private int serialRate;
public SerialMonitor(String port) { public SerialMonitor(String port) {
@ -46,172 +35,57 @@ public class SerialMonitor extends JFrame implements MessageConsumer {
this.port = port; this.port = port;
addWindowListener(new WindowAdapter() { onSerialRateChange(new ActionListener() {
public void windowClosing(WindowEvent e) {
closeSerialPort();
}
});
// obvious, no?
KeyStroke wc = Editor.WINDOW_CLOSE_KEYSTROKE;
getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(wc, "close");
getRootPane().getActionMap().put("close", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
closeSerialPort();
setVisible(false);
}});
getContentPane().setLayout(new BorderLayout());
Font consoleFont = Theme.getFont("console.font");
Font editorFont = Preferences.getFont("editor.font");
Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize());
textArea = new JTextArea(16, 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 pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
textField = new JTextField(40);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send(textField.getText());
textField.setText("");
}});
sendButton = new JButton(_("Send"));
sendButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send(textField.getText());
textField.setText("");
}});
pane.add(textField);
pane.add(Box.createRigidArea(new Dimension(4, 0)));
pane.add(sendButton);
getContentPane().add(pane, BorderLayout.NORTH);
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.X_AXIS));
pane.setBorder(new EmptyBorder(4, 4, 4, 4));
autoscrollBox = new JCheckBox(_("Autoscroll"), true);
lineEndings = new JComboBox(new String[] { _("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR") });
lineEndings.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
Preferences.setInteger("serial.line_ending", lineEndings.getSelectedIndex());
}
});
if (Preferences.get("serial.line_ending") != null) {
lineEndings.setSelectedIndex(Preferences.getInteger("serial.line_ending"));
}
lineEndings.setMaximumSize(lineEndings.getMinimumSize());
String[] serialRateStrings = {
"300","1200","2400","4800","9600",
"19200","57600","115200"
};
serialRates = new JComboBox();
for (int i = 0; i < serialRateStrings.length; i++)
serialRates.addItem(serialRateStrings[i] + " " + _("baud"));
serialRate = Preferences.getInteger("serial.debug_rate");
serialRates.setSelectedItem(serialRate + " " + _("baud"));
serialRates.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
String wholeString = (String) serialRates.getSelectedItem(); String wholeString = (String) serialRates.getSelectedItem();
String rateString = wholeString.substring(0, wholeString.indexOf(' ')); String rateString = wholeString.substring(0, wholeString.indexOf(' '));
serialRate = Integer.parseInt(rateString); serialRate = Integer.parseInt(rateString);
Preferences.set("serial.debug_rate", rateString); Preferences.set("serial.debug_rate", rateString);
closeSerialPort();
try { try {
close();
Thread.sleep(100); // Wait for serial port to properly close Thread.sleep(100); // Wait for serial port to properly close
openSerialPort(); open();
} catch (SerialException e) { } catch (IOException e) {
System.err.println(e); System.err.println(e);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
}});
serialRates.setMaximumSize(serialRates.getMinimumSize());
pane.add(autoscrollBox);
pane.add(Box.createHorizontalGlue());
pane.add(lineEndings);
pane.add(Box.createRigidArea(new Dimension(8, 0)));
pane.add(serialRates);
getContentPane().add(pane, BorderLayout.SOUTH);
pack();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
if (Preferences.get("last.screen.height") != null) {
// if screen size has changed, the window coordinates no longer
// make sense, so don't use them unless they're identical
int screenW = Preferences.getInteger("last.screen.width");
int screenH = Preferences.getInteger("last.screen.height");
if ((screen.width == screenW) && (screen.height == screenH)) {
String locationStr = Preferences.get("last.serial.location");
if (locationStr != null) {
int[] location = PApplet.parseInt(PApplet.split(locationStr, ','));
setPlacement(location);
}
}
}
} }
});
protected void setPlacement(int[] location) { onSendCommand(new ActionListener() {
setBounds(location[0], location[1], location[2], location[3]); public void actionPerformed(ActionEvent e) {
send(textField.getText());
textField.setText("");
} }
});
protected int[] getPlacement() {
int[] location = new int[4];
// Get the dimensions of the Frame
Rectangle bounds = getBounds();
location[0] = bounds.x;
location[1] = bounds.y;
location[2] = bounds.width;
location[3] = bounds.height;
return location;
} }
private void send(String s) { private void send(String s) {
if (serial != null) { if (serial != null) {
switch (lineEndings.getSelectedIndex()) { switch (lineEndings.getSelectedIndex()) {
case 1: s += "\n"; break; case 1:
case 2: s += "\r"; break; s += "\n";
case 3: s += "\r\n"; break; break;
case 2:
s += "\r";
break;
case 3:
s += "\r\n";
break;
} }
serial.write(s); serial.write(s);
} }
} }
public void openSerialPort() throws SerialException { public void open() throws IOException {
if (serial != null) return; if (serial != null) return;
serial = new Serial(port, serialRate); serial = new Serial(port, serialRate);
serial.addListener(this); serial.addListener(this);
} }
public void closeSerialPort() { public void close() throws IOException {
if (serial != null) { if (serial != null) {
int[] location = getPlacement(); int[] location = getPlacement();
String locationStr = PApplet.join(PApplet.str(location), ","); String locationStr = PApplet.join(PApplet.str(location), ",");
@ -221,14 +95,4 @@ public class SerialMonitor extends JFrame implements MessageConsumer {
serial = null; serial = null;
} }
} }
public void message(final String s) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(s);
if (autoscrollBox.isSelected()) {
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}});
}
} }

View File

@ -1580,7 +1580,7 @@ public class Sketch {
* Handle export to applet. * Handle export to applet.
*/ */
public boolean exportApplet(String appletPath, boolean usingProgrammer) public boolean exportApplet(String appletPath, boolean usingProgrammer)
throws RunnerException, IOException, SerialException { throws RunnerException, IOException {
prepare(); prepare();
@ -1658,12 +1658,12 @@ public class Sketch {
System.out.println(_("Low memory available, stability problems may occur")); System.out.println(_("Low memory available, stability problems may occur"));
} }
protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws RunnerException, SerialException { protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws RunnerException {
TargetPlatform target = Base.getTargetPlatform(); TargetPlatform target = Base.getTargetPlatform();
String board = Preferences.get("board"); String board = Preferences.get("board");
Uploader uploader = new UploaderFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port")); Uploader uploader = new PerPortObjectFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port"));
boolean success = false; boolean success = false;
do { do {

View File

@ -45,7 +45,7 @@ public class BasicUploader extends Uploader {
public boolean uploadUsingPreferences(String buildPath, String className, public boolean uploadUsingPreferences(String buildPath, String className,
boolean usingProgrammer) boolean usingProgrammer)
throws RunnerException, SerialException { throws RunnerException {
// FIXME: Preferences should be reorganized // FIXME: Preferences should be reorganized
TargetPlatform targetPlatform = Base.getTargetPlatform(); TargetPlatform targetPlatform = Base.getTargetPlatform();
PreferencesMap prefs = Preferences.getMap(); PreferencesMap prefs = Preferences.getMap();
@ -152,7 +152,11 @@ public class BasicUploader extends Uploader {
Thread.sleep(250); Thread.sleep(250);
} }
} else { } else {
try {
Serial.touchPort(uploadPort, 9600); Serial.touchPort(uploadPort, 9600);
} catch (SerialException e) {
throw new RunnerException(e);
}
} }
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {

View File

@ -7,8 +7,8 @@ import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PostMethod;
import processing.app.Base; import processing.app.Base;
import processing.app.Constants;
import processing.app.Preferences; import processing.app.Preferences;
import processing.app.SerialException;
import processing.app.helpers.PreferencesMap; import processing.app.helpers.PreferencesMap;
import java.io.*; import java.io.*;
@ -19,7 +19,6 @@ import java.util.regex.Pattern;
public class HttpUploader extends Uploader { public class HttpUploader extends Uploader {
private static final Pattern IPV4_ADDRESS = Pattern.compile("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
private static final String PROTOCOL = "http://"; private static final String PROTOCOL = "http://";
/* /*
@ -34,11 +33,11 @@ public class HttpUploader extends Uploader {
public HttpUploader(String port) { public HttpUploader(String port) {
this.client = new HttpClient(); this.client = new HttpClient();
Matcher matcher = IPV4_ADDRESS.matcher(port); Matcher matcher = Constants.IPV4_ADDRESS.matcher(port);
if (!matcher.find()) { if (!matcher.find()) {
throw new IllegalArgumentException(port); throw new IllegalArgumentException(port);
} }
this.ipAddress = matcher.group(1); this.ipAddress = matcher.group();
this.baseUrl = PROTOCOL + ipAddress + "/cgi-bin/luci/arduino"; this.baseUrl = PROTOCOL + ipAddress + "/cgi-bin/luci/arduino";
} }
@ -51,7 +50,7 @@ public class HttpUploader extends Uploader {
} }
@Override @Override
public boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer) throws RunnerException, SerialException { public boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer) throws RunnerException {
if (usingProgrammer) { if (usingProgrammer) {
System.err.println("Http upload using programmer not supported"); System.err.println("Http upload using programmer not supported");
return false; return false;

View File

@ -23,21 +23,26 @@
package processing.app.debug; package processing.app.debug;
import java.io.*; import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
/** /**
* Slurps up messages from compiler. * Slurps up messages from compiler.
*/ */
public class MessageSiphon implements Runnable { public class MessageSiphon implements Runnable {
BufferedReader streamReader;
Thread thread;
MessageConsumer consumer;
private final BufferedReader streamReader;
private final MessageConsumer consumer;
private Thread thread;
private boolean canRun;
public MessageSiphon(InputStream stream, MessageConsumer consumer) { public MessageSiphon(InputStream stream, MessageConsumer consumer) {
this.streamReader = new BufferedReader(new InputStreamReader(stream)); this.streamReader = new BufferedReader(new InputStreamReader(stream));
this.consumer = consumer; this.consumer = consumer;
this.canRun = true;
thread = new Thread(this); thread = new Thread(this);
// don't set priority too low, otherwise exceptions won't // don't set priority too low, otherwise exceptions won't
@ -55,19 +60,17 @@ public class MessageSiphon implements Runnable {
// when the program is finally done, null will come through. // when the program is finally done, null will come through.
// //
String currentLine; String currentLine;
while ((currentLine = streamReader.readLine()) != null) { while (canRun && (currentLine = streamReader.readLine()) != null) {
// \n is added again because readLine() strips it out // \n is added again because readLine() strips it out
//EditorConsole.systemOut.println("messaging in"); //EditorConsole.systemOut.println("messaging in");
consumer.message(currentLine + "\n"); consumer.message(currentLine + "\n");
//EditorConsole.systemOut.println("messaging out"); //EditorConsole.systemOut.println("messaging out");
} }
//EditorConsole.systemOut.println("messaging thread done"); //EditorConsole.systemOut.println("messaging thread done");
thread = null;
} catch (NullPointerException npe) { } catch (NullPointerException npe) {
// Fairly common exception during shutdown // Fairly common exception during shutdown
thread = null; } catch (SocketException e) {
// socket has been close while we were wainting for data. nothing to see here, move along
} catch (Exception e) { } catch (Exception e) {
// On Linux and sometimes on Mac OS X, a "bad file descriptor" // On Linux and sometimes on Mac OS X, a "bad file descriptor"
// message comes up when closing an applet that's run externally. // message comes up when closing an applet that's run externally.
@ -81,6 +84,7 @@ public class MessageSiphon implements Runnable {
} else { } else {
e.printStackTrace(); e.printStackTrace();
} }
} finally {
thread = null; thread = null;
} }
} }
@ -93,7 +97,8 @@ public class MessageSiphon implements Runnable {
if (t != null) t.join(); if (t != null) t.join();
} }
public Thread getThread() { public void stop() {
return thread; this.canRun = false;
} }
} }

View File

@ -52,7 +52,7 @@ public abstract class Uploader implements MessageConsumer {
boolean verbose; boolean verbose;
public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer) public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer)
throws RunnerException, SerialException; throws RunnerException;
public abstract boolean burnBootloader() throws RunnerException; public abstract boolean burnBootloader() throws RunnerException;

View File

@ -1,18 +0,0 @@
package processing.app.debug;
import java.util.Map;
import java.util.regex.Pattern;
public class UploaderFactory {
private static final Pattern IPV4_ADDRESS = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
public Uploader newUploader(TargetBoard board, String port) {
if ("true".equals(board.getPreferences().get("upload.via_http")) && IPV4_ADDRESS.matcher(port).find()) {
return new HttpUploader(port);
}
return new BasicUploader();
}
}

View File

@ -3,6 +3,7 @@ package processing.app.debug;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import processing.app.AbstractWithPreferencesTest; import processing.app.AbstractWithPreferencesTest;
import processing.app.PerPortObjectFactory;
import processing.app.helpers.PreferencesMap; import processing.app.helpers.PreferencesMap;
import java.io.File; import java.io.File;
@ -23,7 +24,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfHttpUploader() throws Exception { public void shouldCreateAnInstanceOfHttpUploader() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun"); TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun");
Uploader uploader = new UploaderFactory().newUploader(board, "192.168.0.1 (yun)"); Uploader uploader = new PerPortObjectFactory().newUploader(board, "192.168.0.1 (yun)");
assertTrue(uploader instanceof HttpUploader); assertTrue(uploader instanceof HttpUploader);
} }
@ -31,7 +32,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfBasicUploaderWhenHTTPIsUnsupported() throws Exception { public void shouldCreateAnInstanceOfBasicUploaderWhenHTTPIsUnsupported() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno"); TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new UploaderFactory().newUploader(board, "192.168.0.1 (myyun)"); Uploader uploader = new PerPortObjectFactory().newUploader(board, "192.168.0.1 (myyun)");
assertTrue(uploader instanceof BasicUploader); assertTrue(uploader instanceof BasicUploader);
} }
@ -39,7 +40,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception { public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno"); TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new UploaderFactory().newUploader(board, "/dev/ttyACM0 (Arduino Leonardo)"); Uploader uploader = new PerPortObjectFactory().newUploader(board, "/dev/ttyACM0 (Arduino Leonardo)");
assertTrue(uploader instanceof BasicUploader); assertTrue(uploader instanceof BasicUploader);
} }