blob: 202e1793265b18a18bdabfe907eb9e02780aab29 [file] [log] [blame]
/* -*- 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.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, SerialException {
// 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 use1200bpsTouch = prefs.get("upload.use_1200bps_touch");
boolean doTouch = use1200bpsTouch != null && use1200bpsTouch.equals("true");
if (doTouch) {
String uploadPort = prefs.get("serial.port");
String caterinaUploadPort = null;
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);
// 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);
}
// 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) {
caterinaUploadPort = diff.get(0);
if (verbose || Preferences.getBoolean("upload.verbose"))
System.out.println("Found Leonardo upload port: " +
caterinaUploadPort);
break;
}
// 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);
caterinaUploadPort = uploadPort;
break;
}
}
if (caterinaUploadPort == null)
// Something happened while detecting port
throw new RunnerException(
_("Couldn’t find a Leonardo 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."));
uploadPort = caterinaUploadPort;
} catch (SerialException e) {
throw new RunnerException(e.getMessage());
} catch (InterruptedException e) {
throw new RunnerException(e.getMessage());
}
prefs.put("serial.port", 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);
}
// For 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.
try {
if (uploadResult && doTouch) {
Thread.sleep(500);
long timeout = System.currentTimeMillis() + 2000;
while (timeout > System.currentTimeMillis()) {
List<String> portList = Serial.list();
if (portList.contains(Preferences.get("serial.port")))
break;
Thread.sleep(100);
}
}
} catch (InterruptedException ex) {
}
return uploadResult;
}
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 {
String programmer = Preferences.get("programmer");
TargetPlatform targetPlatform = Base.getTargetPlatform();
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("bootloader.tool")));
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 {
// if (prefs.get("program.disable_flushing") == null
// || prefs.get("program.disable_flushing").toLowerCase().equals("false"))
// {
// flushSerialBuffer();
// }
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);
}
}
}