| /* -*- 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); |
| } |
| } |
| } |