First refactoring of uploaders

This commit is contained in:
Cristian Maglie 2013-06-03 00:44:15 +02:00
parent 6b05276b7e
commit 4b0a976686
10 changed files with 495 additions and 580 deletions

View File

@ -0,0 +1,137 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Uploader - abstract uploading baseclass (common to both uisp and avrdude)
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2004-05
Hernando Barragan
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
$Id$
*/
package cc.arduino.packages;
import static processing.app.I18n._;
import java.util.Collection;
import processing.app.I18n;
import processing.app.Preferences;
import processing.app.debug.MessageConsumer;
import processing.app.debug.MessageSiphon;
import processing.app.debug.RunnerException;
public abstract class Uploader implements MessageConsumer {
private String error = null;
protected boolean verbose = Preferences.getBoolean("upload.verbose");
public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer)
throws RunnerException;
public abstract boolean burnBootloader() throws RunnerException;
public boolean requiresAuthorization() {
return false;
}
public String getAuthorizationKey() {
return null;
}
protected boolean executeUploadCommand(Collection<String> command)
throws RunnerException {
return executeUploadCommand(command.toArray(new String[0]));
}
protected boolean executeUploadCommand(String command[])
throws RunnerException {
notFoundError = false;
int result = -1;
try {
if (verbose) {
for (String c : command)
System.out.print(c + " ");
System.out.println();
}
Process process = Runtime.getRuntime().exec(command);
new MessageSiphon(process.getInputStream(), this);
new MessageSiphon(process.getErrorStream(), this);
// wait for the process to finish.
result = process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
if (error != null) {
RunnerException exception = new RunnerException(error);
exception.hideStackTrace();
throw exception;
}
return result == 0;
}
boolean notFoundError;
public void message(String s) {
// selectively suppress a bunch of avrdude output for AVR109/Caterina that should already be quelled but isn't
if (!verbose && (
s.indexOf("Connecting to programmer:") != -1 ||
s.indexOf("Found programmer: Id = \"CATERIN\"; type = S") != -1 ||
s.indexOf("Software Version = 1.0; No Hardware Version given.") != -1 ||
s.indexOf("Programmer supports auto addr increment.") != -1 ||
s.indexOf("Programmer supports buffered memory access with buffersize=128 bytes.") != -1 ||
s.indexOf("Programmer supports the following devices:") != -1 ||
s.indexOf("Device code: 0x44") != -1))
s = "";
System.err.print(s);
// ignore cautions
if (s.contains("Error")) {
notFoundError = true;
return;
}
if (notFoundError) {
error = I18n.format(_("the selected serial port {0} does not exist or your board is not connected"), s);
return;
}
if (s.contains("Device is not responding")) {
error = _("Device is not responding, check the right serial port is selected or RESET the board right before exporting");
return;
}
if (s.contains("Programmer is not responding") ||
s.contains("programmer is not responding") ||
s.contains("protocol error") ||
s.contains("avrdude: ser_open(): can't open device") ||
s.contains("avrdude: ser_drain(): read error") ||
s.contains("avrdude: ser_send(): write error") ||
s.contains("avrdude: error: buffered memory access not supported.")) {
error = _("Problem uploading to board. See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions.");
return;
}
if (s.contains("Expected signature")) {
error = _("Wrong microcontroller found. Did you select the right board from the Tools > Board menu?");
return;
}
}
}

View File

@ -1,20 +1,22 @@
package processing.app;
package cc.arduino.packages;
import processing.app.debug.BasicUploader;
import processing.app.debug.HttpUploader;
import processing.app.AbstractMonitor;
import processing.app.Base;
import processing.app.Constants;
import processing.app.NetworkMonitor;
import processing.app.SerialMonitor;
import processing.app.debug.TargetBoard;
import processing.app.debug.Uploader;
import cc.arduino.packages.uploaders.HttpUploader;
import cc.arduino.packages.uploaders.SerialUploader;
import java.util.regex.Pattern;
public class PerPortObjectFactory {
public class UploaderFactory {
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();
return new SerialUploader();
}
public AbstractMonitor newMonitor(String port, Base base) {

View File

@ -1,4 +1,4 @@
package processing.app.debug;
package cc.arduino.packages.uploaders;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
@ -6,9 +6,14 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import cc.arduino.packages.Uploader;
import processing.app.Base;
import processing.app.Constants;
import processing.app.Preferences;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform;
import processing.app.helpers.PreferencesMap;
import java.io.*;

View File

@ -1,7 +1,322 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
BasicUploader - generic command line uploader implementation
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2004-05
Hernando Barragan
Copyright (c) 2012
Cristian Maglie <c.maglie@bug.st>
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
$Id$
*/
package cc.arduino.packages.uploaders;
import static processing.app.I18n._;
import java.util.ArrayList;
import java.util.List;
import cc.arduino.packages.Uploader;
public class SerialUploader implements Uploader {
import processing.app.Base;
import processing.app.I18n;
import processing.app.Preferences;
import processing.app.Serial;
import processing.app.SerialException;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.StringReplacer;
public class SerialUploader extends Uploader {
public boolean uploadUsingPreferences(String buildPath, String className,
boolean usingProgrammer)
throws RunnerException {
// FIXME: Preferences should be reorganized
TargetPlatform targetPlatform = Base.getTargetPlatform();
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
// if no protocol is specified for this board, assume it lacks a
// bootloader and upload using the selected programmer.
if (usingProgrammer || prefs.get("upload.protocol") == null) {
return uploadUsingProgrammer(buildPath, className);
}
// need to do a little dance for Leonardo and derivatives:
// open then close the port at the magic baudrate (usually 1200 bps) first
// to signal to the sketch that it should reset into bootloader. after doing
// this wait a moment for the bootloader to enumerate. On Windows, also must
// deal with the fact that the COM port number changes from bootloader to
// sketch.
String t = prefs.get("upload.use_1200bps_touch");
boolean doTouch = t != null && t.equals("true");
t = prefs.get("upload.wait_for_upload_port");
boolean waitForUploadPort = (t != null) && t.equals("true");
if (doTouch) {
String uploadPort = prefs.get("serial.port");
try {
// Toggle 1200 bps on selected serial port to force board reset.
List<String> before = Serial.list();
if (before.contains(uploadPort)) {
if (verbose)
System.out
.println(_("Forcing reset using 1200bps open/close on port ") +
uploadPort);
Serial.touchPort(uploadPort, 1200);
}
if (waitForUploadPort) {
// Scanning for available ports seems to open the port or
// otherwise assert DTR, which would cancel the WDT reset if
// it happened within 250 ms. So we wait until the reset should
// have already occured before we start scanning.
if (!Base.isMacOS())
Thread.sleep(300);
uploadPort = waitForUploadPort(uploadPort, before);
} else {
Thread.sleep(400);
}
} catch (SerialException e) {
throw new RunnerException(e.getMessage());
} catch (InterruptedException e) {
throw new RunnerException(e.getMessage());
}
prefs.put("serial.port", uploadPort);
if (uploadPort.startsWith("/dev/"))
prefs.put("serial.port.file", uploadPort.substring(5));
else
prefs.put("serial.port.file", uploadPort);
}
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
if (verbose)
prefs.put("upload.verbose", prefs.get("upload.params.verbose"));
else
prefs.put("upload.verbose", prefs.get("upload.params.quiet"));
boolean uploadResult;
try {
// if (prefs.get("upload.disable_flushing") == null
// || prefs.get("upload.disable_flushing").toLowerCase().equals("false")) {
// flushSerialBuffer();
// }
String pattern = prefs.get("upload.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
uploadResult = executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
// Remove the magic baud rate (1200bps) to avoid
// future unwanted board resets
try {
if (uploadResult && doTouch) {
String uploadPort = Preferences.get("serial.port");
if (waitForUploadPort) {
// For Due/Leonardo wait until the bootloader serial port disconnects and the
// sketch serial port reconnects (or timeout after a few seconds if the
// sketch port never comes back). Doing this saves users from accidentally
// opening Serial Monitor on the soon-to-be-orphaned bootloader port.
Thread.sleep(500);
long timeout = System.currentTimeMillis() + 2000;
while (timeout > System.currentTimeMillis()) {
List<String> portList = Serial.list();
if (portList.contains(uploadPort)) {
try {
Serial.touchPort(uploadPort, 9600);
break;
} catch (SerialException e) {
// Port already in use
}
}
Thread.sleep(250);
}
} else {
try {
Serial.touchPort(uploadPort, 9600);
} catch (SerialException e) {
throw new RunnerException(e);
}
}
}
} catch (InterruptedException ex) {
}
return uploadResult;
}
private String waitForUploadPort(String uploadPort, List<String> before)
throws InterruptedException, RunnerException {
// Wait for a port to appear on the list
int elapsed = 0;
while (elapsed < 10000) {
List<String> now = Serial.list();
List<String> diff = new ArrayList<String>(now);
diff.removeAll(before);
if (verbose) {
System.out.print("PORTS {");
for (String p : before)
System.out.print(p + ", ");
System.out.print("} / {");
for (String p : now)
System.out.print(p + ", ");
System.out.print("} => {");
for (String p : diff)
System.out.print(p + ", ");
System.out.println("}");
}
if (diff.size() > 0) {
String newPort = diff.get(0);
if (verbose)
System.out.println("Found upload port: " + newPort);
return newPort;
}
// Keep track of port that disappears
before = now;
Thread.sleep(250);
elapsed += 250;
// On Windows, it can take a long time for the port to disappear and
// come back, so use a longer time out before assuming that the
// selected
// port is the bootloader (not the sketch).
if (((!Base.isWindows() && elapsed >= 500) || elapsed >= 5000) &&
now.contains(uploadPort)) {
if (verbose)
System.out.println("Uploading using selected port: " +
uploadPort);
return uploadPort;
}
}
// Something happened while detecting port
throw new RunnerException(
_("Couldn't find a Board on the selected port. Check that you have the correct port selected. If it is correct, try pressing the board's reset button after initiating the upload."));
}
public boolean uploadUsingProgrammer(String buildPath, String className)
throws RunnerException {
TargetPlatform targetPlatform = Base.getTargetPlatform();
String programmer = Preferences.get("programmer");
if (programmer.contains(":")) {
String[] split = programmer.split(":", 2);
targetPlatform = Base.getCurrentTargetPlatformFromPackage(split[0]);
programmer = split[1];
}
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(targetPlatform.getProgrammer(programmer));
prefs.putAll(targetPlatform.getTool(prefs.get("program.tool")));
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
if (verbose)
prefs.put("program.verbose", prefs.get("program.params.verbose"));
else
prefs.put("program.verbose", prefs.get("program.params.quiet"));
try {
// if (prefs.get("program.disable_flushing") == null
// || prefs.get("program.disable_flushing").toLowerCase().equals("false"))
// {
// flushSerialBuffer();
// }
String pattern = prefs.get("program.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
return executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
}
public boolean burnBootloader() throws RunnerException {
TargetPlatform targetPlatform = Base.getTargetPlatform();
// Find preferences for the selected programmer
PreferencesMap programmerPrefs;
String programmer = Preferences.get("programmer");
if (programmer.contains(":")) {
String[] split = programmer.split(":", 2);
TargetPlatform platform = Base
.getCurrentTargetPlatformFromPackage(split[0]);
programmer = split[1];
programmerPrefs = platform.getProgrammer(programmer);
} else {
programmerPrefs = targetPlatform.getProgrammer(programmer);
}
// Build configuration for the current programmer
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(programmerPrefs);
// Create configuration for bootloader tool
PreferencesMap toolPrefs = new PreferencesMap();
String tool = prefs.get("bootloader.tool");
if (tool.contains(":")) {
String[] split = tool.split(":", 2);
TargetPlatform platform = Base.getCurrentTargetPlatformFromPackage(split[0]);
tool = split[1];
toolPrefs.putAll(platform.getTool(tool));
if (toolPrefs.size() == 0)
throw new RunnerException(
I18n.format(_("Could not find tool {0} from package {1}"), tool,
split[0]));
}
toolPrefs.putAll(targetPlatform.getTool(tool));
if (toolPrefs.size() == 0)
throw new RunnerException(I18n.format(_("Could not find tool {0}"),
tool));
// Merge tool with global configuration
prefs.putAll(toolPrefs);
if (verbose) {
prefs.put("erase.verbose", prefs.get("erase.params.verbose"));
prefs.put("bootloader.verbose", prefs.get("bootloader.params.verbose"));
} else {
prefs.put("erase.verbose", prefs.get("erase.params.quiet"));
prefs.put("bootloader.verbose", prefs.get("bootloader.params.quiet"));
}
try {
String pattern = prefs.get("erase.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
if (!executeUploadCommand(cmd))
return false;
pattern = prefs.get("bootloader.pattern");
cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
return executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
}
}

View File

@ -44,6 +44,9 @@ import javax.swing.text.*;
import javax.swing.undo.*;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderFactory;
import cc.arduino.packages.uploaders.SerialUploader;
/**
* Main editor panel for the Processing Development Environment.
@ -204,7 +207,7 @@ public class Editor extends JFrame implements RunnerListener {
//sketchbook = new Sketchbook(this);
if (serialMonitor == null) {
serialMonitor = new PerPortObjectFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor = new UploaderFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor.setIconImage(getIconImage());
}
@ -970,7 +973,7 @@ public class Editor extends JFrame implements RunnerListener {
// ignore
}
serialMonitor.setVisible(false);
serialMonitor = new PerPortObjectFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor = new UploaderFactory().newMonitor(Preferences.get("serial.port"), base);
onBoardOrPortChange();
@ -2507,7 +2510,7 @@ public class Editor extends JFrame implements RunnerListener {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Uploader uploader = new BasicUploader();
Uploader uploader = new SerialUploader();
if (uploader.burnBootloader()) {
statusNotice(_("Done burning bootloader."));
} else {

View File

@ -5,23 +5,21 @@ import processing.app.debug.MessageSiphon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.regex.Matcher;
@SuppressWarnings("serial")
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();
@ -30,9 +28,10 @@ public class NetworkMonitor extends AbstractMonitor {
onSendCommand(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
socket.getOutputStream().write(textField.getText().getBytes());
socket.getOutputStream().write('\n');
socket.getOutputStream().flush();
OutputStream out = socket.getOutputStream();
out.write(textField.getText().getBytes());
out.write('\n');
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
@ -54,14 +53,6 @@ public class NetworkMonitor extends AbstractMonitor {
}
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// ignore
}
}
@Override
public void close() throws IOException {
if (socket != null) {

View File

@ -24,6 +24,9 @@
package processing.app;
import org.apache.commons.codec.digest.DigestUtils;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderFactory;
import processing.app.debug.*;
import processing.app.debug.Compiler;
import processing.app.forms.PasswordAuthorizationDialog;
@ -1663,7 +1666,7 @@ public class Sketch {
TargetPlatform target = Base.getTargetPlatform();
String board = Preferences.get("board");
Uploader uploader = new PerPortObjectFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port"));
Uploader uploader = new UploaderFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port"));
boolean success = false;
do {

View File

@ -1,318 +0,0 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
BasicUploader - generic command line uploader implementation
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2004-05
Hernando Barragan
Copyright (c) 2012
Cristian Maglie <c.maglie@bug.st>
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
$Id$
*/
package processing.app.debug;
import java.util.ArrayList;
import java.util.List;
import processing.app.Base;
import processing.app.I18n;
import processing.app.Preferences;
import processing.app.Serial;
import processing.app.SerialException;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.StringReplacer;
import static processing.app.I18n._;
public class BasicUploader extends Uploader {
public boolean uploadUsingPreferences(String buildPath, String className,
boolean usingProgrammer)
throws RunnerException {
// FIXME: Preferences should be reorganized
TargetPlatform targetPlatform = Base.getTargetPlatform();
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
// if no protocol is specified for this board, assume it lacks a
// bootloader and upload using the selected programmer.
if (usingProgrammer || prefs.get("upload.protocol") == null) {
return uploadUsingProgrammer(buildPath, className);
}
// need to do a little dance for Leonardo and derivatives:
// open then close the port at the magic baudrate (usually 1200 bps) first
// to signal to the sketch that it should reset into bootloader. after doing
// this wait a moment for the bootloader to enumerate. On Windows, also must
// deal with the fact that the COM port number changes from bootloader to
// sketch.
String t = prefs.get("upload.use_1200bps_touch");
boolean doTouch = t != null && t.equals("true");
t = prefs.get("upload.wait_for_upload_port");
boolean waitForUploadPort = (t != null) && t.equals("true");
if (doTouch) {
String uploadPort = prefs.get("serial.port");
try {
// Toggle 1200 bps on selected serial port to force board reset.
List<String> before = Serial.list();
if (before.contains(uploadPort)) {
if (verbose || Preferences.getBoolean("upload.verbose"))
System.out
.println(_("Forcing reset using 1200bps open/close on port ") +
uploadPort);
Serial.touchPort(uploadPort, 1200);
}
if (waitForUploadPort) {
// Scanning for available ports seems to open the port or
// otherwise assert DTR, which would cancel the WDT reset if
// it happened within 250 ms. So we wait until the reset should
// have already occured before we start scanning.
if (!Base.isMacOS())
Thread.sleep(300);
uploadPort = waitForUploadPort(uploadPort, before);
} else {
Thread.sleep(400);
}
} catch (SerialException e) {
throw new RunnerException(e.getMessage());
} catch (InterruptedException e) {
throw new RunnerException(e.getMessage());
}
prefs.put("serial.port", uploadPort);
if (uploadPort.startsWith("/dev/"))
prefs.put("serial.port.file", uploadPort.substring(5));
else
prefs.put("serial.port.file", uploadPort);
}
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
if (verbose)
prefs.put("upload.verbose", prefs.get("upload.params.verbose"));
else
prefs.put("upload.verbose", prefs.get("upload.params.quiet"));
boolean uploadResult;
try {
// if (prefs.get("upload.disable_flushing") == null
// || prefs.get("upload.disable_flushing").toLowerCase().equals("false")) {
// flushSerialBuffer();
// }
String pattern = prefs.get("upload.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
uploadResult = executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
// Remove the magic baud rate (1200bps) to avoid
// future unwanted board resets
try {
if (uploadResult && doTouch) {
String uploadPort = Preferences.get("serial.port");
if (waitForUploadPort) {
// For Due/Leonardo wait until the bootloader serial port disconnects and the
// sketch serial port reconnects (or timeout after a few seconds if the
// sketch port never comes back). Doing this saves users from accidentally
// opening Serial Monitor on the soon-to-be-orphaned bootloader port.
Thread.sleep(500);
long timeout = System.currentTimeMillis() + 2000;
while (timeout > System.currentTimeMillis()) {
List<String> portList = Serial.list();
if (portList.contains(uploadPort)) {
try {
Serial.touchPort(uploadPort, 9600);
break;
} catch (SerialException e) {
// Port already in use
}
}
Thread.sleep(250);
}
} else {
try {
Serial.touchPort(uploadPort, 9600);
} catch (SerialException e) {
throw new RunnerException(e);
}
}
}
} catch (InterruptedException ex) {
}
return uploadResult;
}
private String waitForUploadPort(String uploadPort, List<String> before)
throws InterruptedException, RunnerException {
// Wait for a port to appear on the list
int elapsed = 0;
while (elapsed < 10000) {
List<String> now = Serial.list();
List<String> diff = new ArrayList<String>(now);
diff.removeAll(before);
if (verbose || Preferences.getBoolean("upload.verbose")) {
System.out.print("PORTS {");
for (String p : before)
System.out.print(p + ", ");
System.out.print("} / {");
for (String p : now)
System.out.print(p + ", ");
System.out.print("} => {");
for (String p : diff)
System.out.print(p + ", ");
System.out.println("}");
}
if (diff.size() > 0) {
String newPort = diff.get(0);
if (verbose || Preferences.getBoolean("upload.verbose"))
System.out.println("Found upload port: " + newPort);
return newPort;
}
// Keep track of port that disappears
before = now;
Thread.sleep(250);
elapsed += 250;
// On Windows, it can take a long time for the port to disappear and
// come back, so use a longer time out before assuming that the
// selected
// port is the bootloader (not the sketch).
if (((!Base.isWindows() && elapsed >= 500) || elapsed >= 5000) &&
now.contains(uploadPort)) {
if (verbose || Preferences.getBoolean("upload.verbose"))
System.out.println("Uploading using selected port: " +
uploadPort);
return uploadPort;
}
}
// Something happened while detecting port
throw new RunnerException(
_("Couldn't find a Board on the selected port. Check that you have the correct port selected. If it is correct, try pressing the board's reset button after initiating the upload."));
}
public boolean uploadUsingProgrammer(String buildPath, String className)
throws RunnerException {
TargetPlatform targetPlatform = Base.getTargetPlatform();
String programmer = Preferences.get("programmer");
if (programmer.contains(":")) {
String[] split = programmer.split(":", 2);
targetPlatform = Base.getCurrentTargetPlatformFromPackage(split[0]);
programmer = split[1];
}
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(targetPlatform.getProgrammer(programmer));
prefs.putAll(targetPlatform.getTool(prefs.get("program.tool")));
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
if (verbose)
prefs.put("program.verbose", prefs.get("program.params.verbose"));
else
prefs.put("program.verbose", prefs.get("program.params.quiet"));
try {
// if (prefs.get("program.disable_flushing") == null
// || prefs.get("program.disable_flushing").toLowerCase().equals("false"))
// {
// flushSerialBuffer();
// }
String pattern = prefs.get("program.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
return executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
}
public boolean burnBootloader() throws RunnerException {
TargetPlatform targetPlatform = Base.getTargetPlatform();
// Find preferences for the selected programmer
PreferencesMap programmerPrefs;
String programmer = Preferences.get("programmer");
if (programmer.contains(":")) {
String[] split = programmer.split(":", 2);
TargetPlatform platform = Base
.getCurrentTargetPlatformFromPackage(split[0]);
programmer = split[1];
programmerPrefs = platform.getProgrammer(programmer);
} else {
programmerPrefs = targetPlatform.getProgrammer(programmer);
}
// Build configuration for the current programmer
PreferencesMap prefs = Preferences.getMap();
prefs.putAll(Base.getBoardPreferences());
prefs.putAll(programmerPrefs);
// Create configuration for bootloader tool
PreferencesMap toolPrefs = new PreferencesMap();
String tool = prefs.get("bootloader.tool");
if (tool.contains(":")) {
String[] split = tool.split(":", 2);
TargetPlatform platform = Base.getCurrentTargetPlatformFromPackage(split[0]);
tool = split[1];
toolPrefs.putAll(platform.getTool(tool));
if (toolPrefs.size() == 0)
throw new RunnerException(
I18n.format(_("Could not find tool {0} from package {1}"), tool,
split[0]));
}
toolPrefs.putAll(targetPlatform.getTool(tool));
if (toolPrefs.size() == 0)
throw new RunnerException(I18n.format(_("Could not find tool {0}"),
tool));
// Merge tool with global configuration
prefs.putAll(toolPrefs);
if (verbose) {
prefs.put("erase.verbose", prefs.get("erase.params.verbose"));
prefs.put("bootloader.verbose", prefs.get("bootloader.params.verbose"));
} else {
prefs.put("erase.verbose", prefs.get("erase.params.quiet"));
prefs.put("bootloader.verbose", prefs.get("bootloader.params.quiet"));
}
try {
String pattern = prefs.get("erase.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
if (!executeUploadCommand(cmd))
return false;
pattern = prefs.get("bootloader.pattern");
cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
return executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
}
}
}

View File

@ -1,227 +0,0 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Uploader - abstract uploading baseclass (common to both uisp and avrdude)
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2004-05
Hernando Barragan
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
$Id$
*/
package processing.app.debug;
import static processing.app.I18n._;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import processing.app.I18n;
import processing.app.Preferences;
import processing.app.Serial;
import processing.app.SerialException;
import processing.app.SerialNotFoundException;
public abstract class Uploader implements MessageConsumer {
static final String BUGS_URL =
_("https://developer.berlios.de/bugs/?group_id=3590");
static final String SUPER_BADNESS =
I18n.format(_("Compiler error, please submit this code to {0}"), BUGS_URL);
RunnerException exception;
static InputStream serialInput;
static OutputStream serialOutput;
boolean verbose;
public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean usingProgrammer)
throws RunnerException;
public abstract boolean burnBootloader() throws RunnerException;
public boolean requiresAuthorization() {
return false;
}
public String getAuthorizationKey() {
return null;
}
protected void flushSerialBuffer() throws RunnerException, SerialException {
// Cleanup the serial buffer
try {
Serial serialPort = new Serial();
while(serialPort.available() > 0) {
serialPort.readBytes();
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
serialPort.setDTR(false);
serialPort.setRTS(false);
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
serialPort.setDTR(true);
serialPort.setRTS(true);
serialPort.dispose();
} catch (SerialNotFoundException e) {
throw e;
} catch(Exception e) {
e.printStackTrace();
throw new RunnerException(e.getMessage());
}
}
protected boolean executeUploadCommand(Collection<String> commandDownloader)
throws RunnerException {
String[] commandArray = new String[commandDownloader.size()];
commandDownloader.toArray(commandArray);
return executeUploadCommand(commandArray);
}
protected boolean executeUploadCommand(String commandArray[])
throws RunnerException
{
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
notFoundError = false;
int result=0; // pre-initialized to quiet a bogus warning from jikes
try {
if (verbose || Preferences.getBoolean("upload.verbose")) {
for(int i = 0; i < commandArray.length; i++) {
System.out.print(commandArray[i] + " ");
}
System.out.println();
}
Process process = Runtime.getRuntime().exec(commandArray);
new MessageSiphon(process.getInputStream(), this);
new MessageSiphon(process.getErrorStream(), this);
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
//
boolean compiling = true;
while (compiling) {
try {
result = process.waitFor();
compiling = false;
} catch (InterruptedException intExc) {
}
}
if(exception!=null) {
exception.hideStackTrace();
throw exception;
}
if(result!=0)
return false;
} catch (Exception e) {
String msg = e.getMessage();
if ((msg != null) && (msg.indexOf("uisp: not found") != -1) && (msg.indexOf("avrdude: not found") != -1)) {
//System.err.println("uisp is missing");
//JOptionPane.showMessageDialog(editor.base,
// "Could not find the compiler.\n" +
// "uisp is missing from your PATH,\n" +
// "see readme.txt for help.",
// "Compiler error",
// JOptionPane.ERROR_MESSAGE);
return false;
} else {
e.printStackTrace();
result = -1;
}
}
//System.out.println("result2 is "+result);
// if the result isn't a known, expected value it means that something
// is fairly wrong, one possibility is that jikes has crashed.
//
if (exception != null) throw exception;
if ((result != 0) && (result != 1 )) {
exception = new RunnerException(SUPER_BADNESS);
//editor.error(exception);
//PdeBase.openURL(BUGS_URL);
//throw new PdeException(SUPER_BADNESS);
}
return (result == 0); // ? true : false;
}
boolean firstErrorFound;
boolean secondErrorFound;
// part of the PdeMessageConsumer interface
//
boolean notFoundError;
public void message(String s) {
// selectively suppress a bunch of avrdude output for AVR109/Caterina that should already be quelled but isn't
if (!Preferences.getBoolean("upload.verbose") && (
s.indexOf("Connecting to programmer:") != -1 ||
s.indexOf("Found programmer: Id = \"CATERIN\"; type = S") != -1 ||
s.indexOf("Software Version = 1.0; No Hardware Version given.") != -1 ||
s.indexOf("Programmer supports auto addr increment.") != -1 ||
s.indexOf("Programmer supports buffered memory access with buffersize=128 bytes.") != -1 ||
s.indexOf("Programmer supports the following devices:") != -1 ||
s.indexOf("Device code: 0x44") != -1))
s = "";
System.err.print(s);
// ignore cautions
if (s.indexOf("Error") != -1) {
//exception = new RunnerException(s+" Check the serial port selected or your Board is connected");
//System.out.println(s);
notFoundError = true;
return;
}
if(notFoundError) {
//System.out.println("throwing something");
exception = new RunnerException(I18n.format(_("the selected serial port {0} does not exist or your board is not connected"), s));
return;
}
if (s.indexOf("Device is not responding") != -1 ) {
exception = new RunnerException(_("Device is not responding, check the right serial port is selected or RESET the board right before exporting"));
return;
}
if (s.indexOf("Programmer is not responding") != -1 ||
s.indexOf("programmer is not responding") != -1 ||
s.indexOf("protocol error") != -1 ||
s.indexOf("avrdude: ser_open(): can't open device") != -1 ||
s.indexOf("avrdude: ser_drain(): read error") != -1 ||
s.indexOf("avrdude: ser_send(): write error") != -1 ||
s.indexOf("avrdude: error: buffered memory access not supported.") != -1) {
exception = new RunnerException(_("Problem uploading to board. See http://www.arduino.cc/en/Guide/Troubleshooting#upload for suggestions."));
return;
}
if (s.indexOf("Expected signature") != -1) {
exception = new RunnerException(_("Wrong microcontroller found. Did you select the right board from the Tools > Board menu?"));
return;
}
}
}

View File

@ -2,8 +2,12 @@ package processing.app.debug;
import org.junit.Before;
import org.junit.Test;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderFactory;
import cc.arduino.packages.uploaders.HttpUploader;
import cc.arduino.packages.uploaders.SerialUploader;
import processing.app.AbstractWithPreferencesTest;
import processing.app.PerPortObjectFactory;
import java.io.File;
@ -21,7 +25,7 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfHttpUploader() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun");
Uploader uploader = new PerPortObjectFactory().newUploader(board, "192.168.0.1 (yun)");
Uploader uploader = new UploaderFactory().newUploader(board, "192.168.0.1 (yun)");
assertTrue(uploader instanceof HttpUploader);
}
@ -29,16 +33,16 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenHTTPIsUnsupported() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new PerPortObjectFactory().newUploader(board, "192.168.0.1 (myyun)");
Uploader uploader = new UploaderFactory().newUploader(board, "192.168.0.1 (myyun)");
assertTrue(uploader instanceof BasicUploader);
assertTrue(uploader instanceof SerialUploader);
}
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new PerPortObjectFactory().newUploader(board, "/dev/ttyACM0 (Arduino Leonardo)");
Uploader uploader = new UploaderFactory().newUploader(board, "/dev/ttyACM0 (Arduino Leonardo)");
assertTrue(uploader instanceof BasicUploader);
assertTrue(uploader instanceof SerialUploader);
}
}