mirror of
https://github.com/esp8266/Arduino.git
synced 2025-08-11 09:43:08 +03:00
Split IDE into 2 projects.
BEWARE: HIGHLY EXPERIMENTAL BRANCH
This commit is contained in:
82
arduino-core/src/cc/arduino/packages/BoardPort.java
Normal file
82
arduino-core/src/cc/arduino/packages/BoardPort.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages;
|
||||
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
|
||||
public class BoardPort {
|
||||
|
||||
private String address;
|
||||
private String protocol;
|
||||
private String boardName;
|
||||
private String label;
|
||||
private PreferencesMap prefs;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getBoardName() {
|
||||
return boardName;
|
||||
}
|
||||
|
||||
public void setBoardName(String boardName) {
|
||||
this.boardName = boardName;
|
||||
}
|
||||
|
||||
public void setPrefs(PreferencesMap prefs) {
|
||||
this.prefs = prefs;
|
||||
}
|
||||
|
||||
public PreferencesMap getPrefs() {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
64
arduino-core/src/cc/arduino/packages/Discovery.java
Normal file
64
arduino-core/src/cc/arduino/packages/Discovery.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages;
|
||||
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Discovery {
|
||||
|
||||
/**
|
||||
* Set discovery preferences
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
public void setPreferences(PreferencesMap options);
|
||||
|
||||
/**
|
||||
* Start discovery service
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void start() throws Exception;
|
||||
|
||||
/**
|
||||
* Stop discovery service
|
||||
*/
|
||||
public void stop() throws Exception;
|
||||
|
||||
/**
|
||||
* Return the list of discovered ports.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<BoardPort> discovery();
|
||||
|
||||
}
|
91
arduino-core/src/cc/arduino/packages/DiscoveryManager.java
Normal file
91
arduino-core/src/cc/arduino/packages/DiscoveryManager.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages;
|
||||
|
||||
import cc.arduino.packages.discoverers.NetworkDiscovery;
|
||||
import cc.arduino.packages.discoverers.SerialDiscovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
public class DiscoveryManager {
|
||||
|
||||
private final List<Discovery> discoverers;
|
||||
|
||||
public DiscoveryManager() {
|
||||
discoverers = new ArrayList<Discovery>();
|
||||
discoverers.add(new SerialDiscovery());
|
||||
discoverers.add(new NetworkDiscovery());
|
||||
|
||||
// Start all discoverers
|
||||
for (Discovery d : discoverers) {
|
||||
try {
|
||||
d.start();
|
||||
} catch (Exception e) {
|
||||
System.err.println(_("Error starting discovery method: ") + d.getClass());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Thread closeHook = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Discovery d : discoverers) {
|
||||
try {
|
||||
d.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Runtime.getRuntime().addShutdownHook(closeHook);
|
||||
}
|
||||
|
||||
public List<BoardPort> discovery() {
|
||||
List<BoardPort> res = new ArrayList<BoardPort>();
|
||||
for (Discovery d : discoverers) {
|
||||
res.addAll(d.discovery());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public BoardPort find(String address) {
|
||||
for (BoardPort boardPort : discovery()) {
|
||||
if (boardPort.getAddress().equals(address)) {
|
||||
return boardPort;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
164
arduino-core/src/cc/arduino/packages/Uploader.java
Normal file
164
arduino-core/src/cc/arduino/packages/Uploader.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
package cc.arduino.packages;
|
||||
|
||||
import processing.app.I18n;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.MessageConsumer;
|
||||
import processing.app.debug.MessageSiphon;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.helpers.ProcessUtils;
|
||||
import processing.app.helpers.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
public abstract class Uploader implements MessageConsumer {
|
||||
|
||||
private static final List<String> STRINGS_TO_SUPPRESS;
|
||||
private static final List<String> AVRDUDE_PROBLEMS;
|
||||
|
||||
static {
|
||||
STRINGS_TO_SUPPRESS = Arrays.asList("Connecting to programmer:",
|
||||
"Found programmer: Id = \"CATERIN\"; type = S",
|
||||
"Software Version = 1.0; No Hardware Version given.",
|
||||
"Programmer supports auto addr increment.",
|
||||
"Programmer supports buffered memory access with buffersize=128 bytes.",
|
||||
"Programmer supports the following devices:", "Device code: 0x44");
|
||||
|
||||
AVRDUDE_PROBLEMS = Arrays.asList("Programmer is not responding",
|
||||
"programmer is not responding",
|
||||
"protocol error", "avrdude: ser_open(): can't open device",
|
||||
"avrdude: ser_drain(): read error",
|
||||
"avrdude: ser_send(): write error",
|
||||
"avrdude: error: buffered memory access not supported.");
|
||||
}
|
||||
|
||||
protected final boolean verbose;
|
||||
|
||||
private String error;
|
||||
protected boolean notFoundError;
|
||||
protected boolean noUploadPort;
|
||||
|
||||
protected Uploader() {
|
||||
this.verbose = PreferencesData.getBoolean("upload.verbose");
|
||||
init(false);
|
||||
}
|
||||
|
||||
protected Uploader(boolean nup) {
|
||||
this.verbose = PreferencesData.getBoolean("upload.verbose");
|
||||
init(nup);
|
||||
}
|
||||
|
||||
private void init(boolean nup) {
|
||||
this.error = null;
|
||||
this.notFoundError = false;
|
||||
this.noUploadPort = nup;
|
||||
}
|
||||
|
||||
public abstract boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws Exception;
|
||||
|
||||
public abstract boolean burnBootloader() throws Exception;
|
||||
|
||||
public boolean requiresAuthorization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getAuthorizationKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean executeUploadCommand(Collection<String> command) throws Exception {
|
||||
return executeUploadCommand(command.toArray(new String[command.size()]));
|
||||
}
|
||||
|
||||
protected boolean executeUploadCommand(String command[]) throws Exception {
|
||||
// Skip empty commands
|
||||
if (command == null || command.length == 0)
|
||||
return true;
|
||||
|
||||
notFoundError = false;
|
||||
int result = -1;
|
||||
|
||||
try {
|
||||
if (verbose) {
|
||||
for (String c : command)
|
||||
System.out.print(c + " ");
|
||||
System.out.println();
|
||||
}
|
||||
Process process = ProcessUtils.exec(command);
|
||||
new MessageSiphon(process.getInputStream(), this, 100);
|
||||
new MessageSiphon(process.getErrorStream(), this, 100);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 && StringUtils.stringContainsOneOf(s, STRINGS_TO_SUPPRESS)) {
|
||||
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 (StringUtils.stringContainsOneOf(s, AVRDUDE_PROBLEMS)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
49
arduino-core/src/cc/arduino/packages/UploaderFactory.java
Normal file
49
arduino-core/src/cc/arduino/packages/UploaderFactory.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages;
|
||||
|
||||
import cc.arduino.packages.uploaders.SSHUploader;
|
||||
import cc.arduino.packages.uploaders.SerialUploader;
|
||||
import processing.app.debug.TargetBoard;
|
||||
|
||||
public class UploaderFactory {
|
||||
|
||||
public Uploader newUploader(TargetBoard board, BoardPort port, boolean noUploadPort) {
|
||||
if (noUploadPort)
|
||||
return new SerialUploader(noUploadPort);
|
||||
|
||||
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && port != null && "network".equals(port.getProtocol())) {
|
||||
return new SSHUploader(port);
|
||||
}
|
||||
|
||||
return new SerialUploader();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.discoverers;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Discovery;
|
||||
import cc.arduino.packages.discoverers.network.*;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.helpers.NetUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter;
|
||||
|
||||
import javax.jmdns.*;
|
||||
import javax.jmdns.impl.DNSTaskStarter;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.*;
|
||||
|
||||
public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.packages.discoverers.network.NetworkTopologyListener {
|
||||
|
||||
private Timer timer;
|
||||
private final List<BoardPort> ports;
|
||||
private final Map<InetAddress, JmDNS> mappedJmDNSs;
|
||||
|
||||
public NetworkDiscovery() {
|
||||
DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter());
|
||||
this.ports = new ArrayList<BoardPort>();
|
||||
this.mappedJmDNSs = new Hashtable<InetAddress, JmDNS>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BoardPort> discovery() {
|
||||
List<BoardPort> ports = clonePortsList();
|
||||
Iterator<BoardPort> iterator = ports.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
try {
|
||||
BoardPort board = iterator.next();
|
||||
if (!NetUtils.isReachable(InetAddress.getByName(board.getAddress()), Integer.parseInt(board.getPrefs().get("port")))) {
|
||||
iterator.remove();
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return ports;
|
||||
}
|
||||
|
||||
private List<BoardPort> clonePortsList() {
|
||||
synchronized (this) {
|
||||
return new ArrayList<BoardPort>(this.ports);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferences(PreferencesMap options) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
this.timer = new Timer(this.getClass().getName() + " timer");
|
||||
new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(timer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws IOException {
|
||||
timer.purge();
|
||||
// we don't close each JmDNS instance as it's too slow
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceAdded(ServiceEvent serviceEvent) {
|
||||
String type = serviceEvent.getType();
|
||||
String name = serviceEvent.getName();
|
||||
|
||||
JmDNS dns = serviceEvent.getDNS();
|
||||
|
||||
dns.requestServiceInfo(type, name);
|
||||
ServiceInfo serviceInfo = dns.getServiceInfo(type, name);
|
||||
if (serviceInfo != null) {
|
||||
dns.requestServiceInfo(type, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceRemoved(ServiceEvent serviceEvent) {
|
||||
String name = serviceEvent.getName();
|
||||
synchronized (this) {
|
||||
for (BoardPort port : ports) {
|
||||
if (port.getBoardName().equals(name))
|
||||
ports.remove(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceResolved(ServiceEvent serviceEvent) {
|
||||
ServiceInfo info = serviceEvent.getInfo();
|
||||
for (InetAddress inetAddress : info.getInet4Addresses()) {
|
||||
String address = inetAddress.getHostAddress();
|
||||
String name = serviceEvent.getName();
|
||||
|
||||
PreferencesMap prefs = null;
|
||||
String board = null;
|
||||
if (info.hasData()) {
|
||||
prefs = new PreferencesMap();
|
||||
board = info.getPropertyString("board");
|
||||
prefs.put("board", board);
|
||||
prefs.put("distro_version", info.getPropertyString("distro_version"));
|
||||
}
|
||||
|
||||
prefs.put("port", "" + info.getPort());
|
||||
|
||||
String label = name + " at " + address;
|
||||
if (board != null) {
|
||||
String boardName = BaseNoGui.getPlatform().resolveDeviceByBoardID(BaseNoGui.packages, board);
|
||||
label += " (" + boardName + ")";
|
||||
}
|
||||
|
||||
BoardPort port = new BoardPort();
|
||||
port.setAddress(address);
|
||||
port.setBoardName(name);
|
||||
port.setProtocol("network");
|
||||
port.setPrefs(prefs);
|
||||
port.setLabel(label);
|
||||
|
||||
synchronized (this) {
|
||||
removeDuplicateBoards(port);
|
||||
ports.add(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeDuplicateBoards(BoardPort newBoard) {
|
||||
Iterator<BoardPort> iterator = ports.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
BoardPort board = iterator.next();
|
||||
if (newBoard.getAddress().equals(board.getAddress())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inetAddressAdded(InetAddress address) {
|
||||
if (mappedJmDNSs.containsKey(address)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JmDNS jmDNS = JmDNS.create(address);
|
||||
jmDNS.addServiceListener("_arduino._tcp.local.", this);
|
||||
mappedJmDNSs.put(address, jmDNS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inetAddressRemoved(InetAddress address) {
|
||||
JmDNS jmDNS = mappedJmDNSs.remove(address);
|
||||
if (jmDNS != null) {
|
||||
try {
|
||||
jmDNS.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.discoverers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.Platform;
|
||||
import processing.app.Serial;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Discovery;
|
||||
|
||||
public class SerialDiscovery implements Discovery {
|
||||
|
||||
@Override
|
||||
public List<BoardPort> discovery() {
|
||||
Platform os = BaseNoGui.getPlatform();
|
||||
String devicesListOutput = os.preListAllCandidateDevices();
|
||||
|
||||
List<BoardPort> res = new ArrayList<BoardPort>();
|
||||
|
||||
List<String> ports = Serial.list();
|
||||
|
||||
for (String port : ports) {
|
||||
String boardName = os.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput);
|
||||
String label = port;
|
||||
if (boardName != null)
|
||||
label += " (" + boardName + ")";
|
||||
|
||||
BoardPort boardPort = new BoardPort();
|
||||
boardPort.setAddress(port);
|
||||
boardPort.setProtocol("serial");
|
||||
boardPort.setBoardName(boardName);
|
||||
boardPort.setLabel(label);
|
||||
res.add(boardPort);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferences(PreferencesMap options) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.discoverers.network;
|
||||
|
||||
import javax.jmdns.NetworkTopologyDiscovery;
|
||||
import java.net.InetAddress;
|
||||
import java.util.*;
|
||||
|
||||
public class NetworkChecker extends TimerTask {
|
||||
|
||||
private final NetworkTopologyListener topologyListener;
|
||||
private final NetworkTopologyDiscovery topology;
|
||||
|
||||
private Set<InetAddress> knownAddresses;
|
||||
|
||||
public NetworkChecker(NetworkTopologyListener topologyListener, NetworkTopologyDiscovery topology) {
|
||||
super();
|
||||
this.topologyListener = topologyListener;
|
||||
this.topology = topology;
|
||||
this.knownAddresses = Collections.synchronizedSet(new HashSet<InetAddress>());
|
||||
}
|
||||
|
||||
public void start(Timer timer) {
|
||||
timer.schedule(this, 0, 3000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
InetAddress[] curentAddresses = topology.getInetAddresses();
|
||||
Set<InetAddress> current = new HashSet<InetAddress>(curentAddresses.length);
|
||||
for (InetAddress address : curentAddresses) {
|
||||
current.add(address);
|
||||
if (!knownAddresses.contains(address)) {
|
||||
topologyListener.inetAddressAdded(address);
|
||||
}
|
||||
}
|
||||
for (InetAddress address : knownAddresses) {
|
||||
if (!current.contains(address)) {
|
||||
topologyListener.inetAddressRemoved(address);
|
||||
}
|
||||
}
|
||||
knownAddresses = current;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.discoverers.network;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface NetworkTopologyListener {
|
||||
|
||||
void inetAddressAdded(InetAddress address);
|
||||
|
||||
void inetAddressRemoved(InetAddress address);
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import com.jcraft.jsch.UserInfo;
|
||||
|
||||
public class NoInteractionUserInfo implements UserInfo {
|
||||
|
||||
private final String password;
|
||||
|
||||
public NoInteractionUserInfo(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public boolean promptYesNo(String str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getPassphrase() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public boolean promptPassphrase(String message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean promptPassword(String message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void showMessage(String message) {
|
||||
}
|
||||
|
||||
}
|
139
arduino-core/src/cc/arduino/packages/ssh/SCP.java
Normal file
139
arduino-core/src/cc/arduino/packages/ssh/SCP.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import com.jcraft.jsch.Channel;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class SCP extends SSH {
|
||||
|
||||
private Channel channel;
|
||||
private OutputStream out;
|
||||
private InputStream in;
|
||||
|
||||
public SCP(Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
try {
|
||||
channel = session.openChannel("exec");
|
||||
((ChannelExec) channel).setCommand("scp -t -r -d /");
|
||||
|
||||
out = channel.getOutputStream();
|
||||
in = channel.getInputStream();
|
||||
|
||||
channel.connect();
|
||||
ensureAcknowledged();
|
||||
} catch (Exception e) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (channel != null) {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ensureAcknowledged() throws IOException {
|
||||
out.flush();
|
||||
|
||||
int b = in.read();
|
||||
|
||||
if (b == 0) return;
|
||||
if (b == -1) return;
|
||||
|
||||
if (b == 1 || b == 2) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SCP error: ");
|
||||
|
||||
int c;
|
||||
do {
|
||||
c = in.read();
|
||||
sb.append((char) c);
|
||||
} while (c != '\n');
|
||||
|
||||
throw new IOException(sb.toString());
|
||||
}
|
||||
|
||||
throw new IOException("Uknown SCP error: " + b);
|
||||
}
|
||||
|
||||
public void sendFile(File localFile) throws IOException {
|
||||
sendFile(localFile, localFile.getName());
|
||||
}
|
||||
|
||||
public void sendFile(File localFile, String remoteFile) throws IOException {
|
||||
out.write(("C0644 " + localFile.length() + " " + remoteFile + "\n").getBytes());
|
||||
ensureAcknowledged();
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(localFile);
|
||||
byte[] buf = new byte[4096];
|
||||
while (true) {
|
||||
int len = fis.read(buf, 0, buf.length);
|
||||
if (len <= 0) break;
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
|
||||
// \0 terminates file
|
||||
buf[0] = 0;
|
||||
out.write(buf, 0, 1);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
ensureAcknowledged();
|
||||
}
|
||||
|
||||
public void startFolder(String folder) throws IOException {
|
||||
out.write(("D0755 0 " + folder + "\n").getBytes());
|
||||
ensureAcknowledged();
|
||||
}
|
||||
|
||||
public void endFolder() throws IOException {
|
||||
out.write("E\n".getBytes());
|
||||
ensureAcknowledged();
|
||||
}
|
||||
|
||||
}
|
114
arduino-core/src/cc/arduino/packages/ssh/SSH.java
Normal file
114
arduino-core/src/cc/arduino/packages/ssh/SSH.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import com.jcraft.jsch.Channel;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class SSH {
|
||||
|
||||
protected final Session session;
|
||||
|
||||
public SSH(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public boolean execSyncCommand(String command) throws JSchException, IOException {
|
||||
return execSyncCommand(command, null, null);
|
||||
}
|
||||
|
||||
public boolean execSyncCommand(String command, PrintStream stdoutConsumer, PrintStream stderrConsumer) throws JSchException, IOException {
|
||||
InputStream stdout = null;
|
||||
InputStream stderr = null;
|
||||
Channel channel = null;
|
||||
try {
|
||||
channel = session.openChannel("exec");
|
||||
((ChannelExec) channel).setCommand(command);
|
||||
|
||||
channel.setInputStream(null);
|
||||
|
||||
stdout = channel.getInputStream();
|
||||
stderr = ((ChannelExec) channel).getErrStream();
|
||||
|
||||
channel.connect();
|
||||
|
||||
int exitCode = consumeOutputSyncAndReturnExitCode(channel, stdout, stdoutConsumer, stderr, stderrConsumer);
|
||||
|
||||
return exitCode == 0;
|
||||
|
||||
} finally {
|
||||
if (stdout != null) {
|
||||
stdout.close();
|
||||
}
|
||||
if (stderr != null) {
|
||||
stderr.close();
|
||||
}
|
||||
if (channel != null) {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int consumeOutputSyncAndReturnExitCode(Channel channel, InputStream stdout, PrintStream stdoutConsumer, InputStream stderr, PrintStream stderrConsumer) throws IOException {
|
||||
byte[] tmp = new byte[102400];
|
||||
while (true) {
|
||||
consumeStream(tmp, stdout, stdoutConsumer);
|
||||
consumeStream(tmp, stderr, stderrConsumer);
|
||||
|
||||
if (channel.isClosed()) {
|
||||
return channel.getExitStatus();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (Exception ee) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeStream(byte[] buffer, InputStream in, PrintStream out) throws IOException {
|
||||
while (in.available() > 0) {
|
||||
int length = in.read(buffer, 0, buffer.length);
|
||||
if (length < 0) {
|
||||
break;
|
||||
}
|
||||
if (out != null) {
|
||||
out.print(new String(buffer, 0, length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface SSHClientSetupChainRing {
|
||||
|
||||
/*
|
||||
Chain is actually useless as default JSCH behaviour is to follow SSH Server authentication methods list
|
||||
*/
|
||||
Session setup(BoardPort port, JSch jSch) throws JSchException, IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import com.jcraft.jsch.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SSHConfigFileSetup implements SSHClientSetupChainRing {
|
||||
|
||||
private final SSHClientSetupChainRing nextChainRing;
|
||||
|
||||
public SSHConfigFileSetup(SSHClientSetupChainRing nextChainRing) {
|
||||
this.nextChainRing = nextChainRing;
|
||||
}
|
||||
|
||||
public Session setup(BoardPort port, JSch jSch) throws JSchException, IOException {
|
||||
String ipAddress = port.getAddress();
|
||||
String hostname = port.getBoardName().contains(".local") ? port.getBoardName() : port.getBoardName() + ".local";
|
||||
|
||||
File sshFolder = new File(System.getProperty("user.home"), ".ssh");
|
||||
File sshConfig = new File(sshFolder, "config");
|
||||
|
||||
if (!sshFolder.exists() || !sshConfig.exists()) {
|
||||
if (nextChainRing != null) {
|
||||
return nextChainRing.setup(port, jSch);
|
||||
}
|
||||
throw new JSchException("Unable to find a way to connect");
|
||||
}
|
||||
|
||||
OpenSSHConfig configRepository = OpenSSHConfig.parseFile(sshConfig.getAbsolutePath());
|
||||
|
||||
jSch.setConfigRepository(new OpenSSHConfigWrapper(configRepository, ipAddress));
|
||||
|
||||
return jSch.getSession(hostname);
|
||||
}
|
||||
|
||||
public static class OpenSSHConfigWrapper implements ConfigRepository {
|
||||
|
||||
private final OpenSSHConfig config;
|
||||
private final String ipAddress;
|
||||
|
||||
public OpenSSHConfigWrapper(OpenSSHConfig config, String ipAddress) {
|
||||
this.config = config;
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config getConfig(String host) {
|
||||
return new ConfigWrapper(config.getConfig(host), ipAddress);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigWrapper implements ConfigRepository.Config {
|
||||
|
||||
private final ConfigRepository.Config config;
|
||||
private final String ipAddress;
|
||||
|
||||
public ConfigWrapper(OpenSSHConfig.Config config, String ipAddress) {
|
||||
this.config = config;
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostname() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUser() {
|
||||
String user = config.getUser();
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return "root";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return config.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return config.getValue(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getValues(String key) {
|
||||
return config.getValues(key);
|
||||
}
|
||||
}
|
||||
}
|
21
arduino-core/src/cc/arduino/packages/ssh/SSHPwdSetup.java
Normal file
21
arduino-core/src/cc/arduino/packages/ssh/SSHPwdSetup.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package cc.arduino.packages.ssh;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import processing.app.PreferencesData;
|
||||
|
||||
public class SSHPwdSetup implements SSHClientSetupChainRing {
|
||||
|
||||
@Override
|
||||
public Session setup(BoardPort port, JSch jSch) throws JSchException {
|
||||
String ipAddress = port.getAddress();
|
||||
|
||||
Session session = jSch.getSession("root", ipAddress, 22);
|
||||
session.setPassword(PreferencesData.get("runtime.pwd." + ipAddress));
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
194
arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java
Normal file
194
arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*
|
||||
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.uploaders;
|
||||
|
||||
import cc.arduino.packages.BoardPort;
|
||||
import cc.arduino.packages.Uploader;
|
||||
import cc.arduino.packages.ssh.*;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
public class SSHUploader extends Uploader {
|
||||
|
||||
private static final List<String> FILES_NOT_TO_COPY = Arrays.asList(".DS_Store", ".Trash", "Thumbs.db", "__MACOSX");
|
||||
|
||||
private final BoardPort port;
|
||||
|
||||
public SSHUploader(BoardPort port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public boolean requiresAuthorization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthorizationKey() {
|
||||
return "runtime.pwd." + port.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws RunnerException {
|
||||
if (usingProgrammer) {
|
||||
throw new RunnerException(_("Network upload using programmer not supported"));
|
||||
}
|
||||
|
||||
Session session = null;
|
||||
SCP scp = null;
|
||||
try {
|
||||
JSch jSch = new JSch();
|
||||
SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
|
||||
session = sshClientSetupChain.setup(port, jSch);
|
||||
|
||||
session.setUserInfo(new NoInteractionUserInfo(PreferencesData.get("runtime.pwd." + port.getAddress())));
|
||||
session.connect(30000);
|
||||
|
||||
scp = new SCP(session);
|
||||
SSH ssh = new SSH(session);
|
||||
|
||||
scpFiles(scp, ssh, sourcePath, buildPath, className, warningsAccumulator);
|
||||
|
||||
return runAVRDude(ssh);
|
||||
} catch (JSchException e) {
|
||||
String message = e.getMessage();
|
||||
if ("Auth cancel".equals(message) || "Auth fail".equals(message)) {
|
||||
return false;
|
||||
}
|
||||
if (e.getMessage().contains("Connection refused")) {
|
||||
throw new RunnerException(I18n.format("Unable to connect to {0}", port.getAddress()));
|
||||
}
|
||||
throw new RunnerException(e);
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
} finally {
|
||||
if (scp != null) {
|
||||
try {
|
||||
scp.close();
|
||||
} catch (IOException e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
}
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean runAVRDude(SSH ssh) throws IOException, JSchException {
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
|
||||
|
||||
String additionalParams = verbose ? prefs.get("upload.params.verbose") : prefs.get("upload.params.quiet");
|
||||
|
||||
boolean success = ssh.execSyncCommand("merge-sketch-with-bootloader.lua /tmp/sketch.hex", System.out, System.err);
|
||||
ssh.execSyncCommand("kill-bridge");
|
||||
success = success && ssh.execSyncCommand("run-avrdude /tmp/sketch.hex '" + additionalParams + "'", System.out, System.err);
|
||||
return success;
|
||||
}
|
||||
|
||||
private void scpFiles(SCP scp, SSH ssh, File sourcePath, String buildPath, String className, List<String> warningsAccumulator) throws JSchException, IOException {
|
||||
try {
|
||||
scp.open();
|
||||
scp.startFolder("tmp");
|
||||
scp.sendFile(new File(buildPath, className + ".hex"), "sketch.hex");
|
||||
scp.endFolder();
|
||||
|
||||
if (canUploadWWWFiles(sourcePath, ssh, warningsAccumulator)) {
|
||||
scp.startFolder("www");
|
||||
scp.startFolder("sd");
|
||||
scp.startFolder(sourcePath.getName());
|
||||
recursiveSCP(new File(sourcePath, "www"), scp);
|
||||
scp.endFolder();
|
||||
scp.endFolder();
|
||||
scp.endFolder();
|
||||
}
|
||||
} finally {
|
||||
scp.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canUploadWWWFiles(File sourcePath, SSH ssh, List<String> warningsAccumulator) throws IOException, JSchException {
|
||||
File www = new File(sourcePath, "www");
|
||||
if (!www.exists() || !www.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
if (!www.canExecute()) {
|
||||
warningsAccumulator.add(_("Problem accessing files in folder ") + www);
|
||||
return false;
|
||||
}
|
||||
if (!ssh.execSyncCommand("special-storage-available")) {
|
||||
warningsAccumulator.add(_("Problem accessing board folder /www/sd"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void recursiveSCP(File from, SCP scp) throws IOException {
|
||||
File[] files = from.listFiles();
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
if (!StringUtils.stringContainsOneOf(file.getName(), FILES_NOT_TO_COPY)) {
|
||||
if (file.isDirectory() && file.canExecute()) {
|
||||
scp.startFolder(file.getName());
|
||||
recursiveSCP(file, scp);
|
||||
scp.endFolder();
|
||||
} else if (file.isFile() && file.canRead()) {
|
||||
scp.sendFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean burnBootloader() throws RunnerException {
|
||||
throw new RunnerException("Can't burn bootloader via SSH");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,340 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
package cc.arduino.packages.uploaders;
|
||||
|
||||
import static processing.app.I18n._;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.I18n;
|
||||
import processing.app.PreferencesData;
|
||||
import processing.app.Serial;
|
||||
import processing.app.SerialException;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.debug.TargetPlatform;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMap;
|
||||
import processing.app.helpers.StringReplacer;
|
||||
import cc.arduino.packages.Uploader;
|
||||
|
||||
public class SerialUploader extends Uploader {
|
||||
|
||||
public SerialUploader()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SerialUploader(boolean noUploadPort)
|
||||
{
|
||||
super(noUploadPort);
|
||||
}
|
||||
|
||||
public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws Exception {
|
||||
// FIXME: Preferences should be reorganized
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
String tool = prefs.getOrExcept("upload.tool");
|
||||
if (tool.contains(":")) {
|
||||
String[] split = tool.split(":", 2);
|
||||
targetPlatform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
tool = split[1];
|
||||
}
|
||||
prefs.putAll(targetPlatform.getTool(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);
|
||||
}
|
||||
|
||||
if (noUploadPort)
|
||||
{
|
||||
prefs.put("build.path", buildPath);
|
||||
prefs.put("build.project_name", className);
|
||||
if (verbose)
|
||||
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.verbose"));
|
||||
else
|
||||
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.quiet"));
|
||||
|
||||
boolean uploadResult;
|
||||
try {
|
||||
String pattern = prefs.getOrExcept("upload.pattern");
|
||||
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
uploadResult = executeUploadCommand(cmd);
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
return uploadResult;
|
||||
}
|
||||
|
||||
// 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.getOrExcept("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);
|
||||
}
|
||||
Thread.sleep(400);
|
||||
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.
|
||||
uploadPort = waitForUploadPort(uploadPort, before);
|
||||
}
|
||||
} catch (SerialException e) {
|
||||
throw new RunnerException(e);
|
||||
} 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.getOrExcept("upload.params.verbose"));
|
||||
else
|
||||
prefs.put("upload.verbose", prefs.getOrExcept("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.getOrExcept("upload.pattern");
|
||||
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
uploadResult = executeUploadCommand(cmd);
|
||||
} catch (RunnerException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (uploadResult && doTouch) {
|
||||
String uploadPort = PreferencesData.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(1000);
|
||||
long started = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - started < 2000) {
|
||||
List<String> portList = Serial.list();
|
||||
if (portList.contains(uploadPort))
|
||||
break;
|
||||
Thread.sleep(250);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
// noop
|
||||
}
|
||||
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 (((!OSUtils.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 Exception {
|
||||
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
String programmer = PreferencesData.get("programmer");
|
||||
if (programmer.contains(":")) {
|
||||
String[] split = programmer.split(":", 2);
|
||||
targetPlatform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
programmer = split[1];
|
||||
}
|
||||
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
PreferencesMap programmerPrefs = targetPlatform.getProgrammer(programmer);
|
||||
if (programmerPrefs == null)
|
||||
throw new RunnerException(
|
||||
_("Please select a programmer from Tools->Programmer menu"));
|
||||
prefs.putAll(programmerPrefs);
|
||||
prefs.putAll(targetPlatform.getTool(prefs.getOrExcept("program.tool")));
|
||||
|
||||
prefs.put("build.path", buildPath);
|
||||
prefs.put("build.project_name", className);
|
||||
|
||||
if (verbose)
|
||||
prefs.put("program.verbose", prefs.getOrExcept("program.params.verbose"));
|
||||
else
|
||||
prefs.put("program.verbose", prefs.getOrExcept("program.params.quiet"));
|
||||
|
||||
try {
|
||||
// if (prefs.get("program.disable_flushing") == null
|
||||
// || prefs.get("program.disable_flushing").toLowerCase().equals("false"))
|
||||
// {
|
||||
// flushSerialBuffer();
|
||||
// }
|
||||
|
||||
String pattern = prefs.getOrExcept("program.pattern");
|
||||
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
return executeUploadCommand(cmd);
|
||||
} catch (RunnerException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean burnBootloader() throws Exception {
|
||||
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
|
||||
|
||||
// Find preferences for the selected programmer
|
||||
PreferencesMap programmerPrefs;
|
||||
String programmer = PreferencesData.get("programmer");
|
||||
if (programmer.contains(":")) {
|
||||
String[] split = programmer.split(":", 2);
|
||||
TargetPlatform platform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
|
||||
programmer = split[1];
|
||||
programmerPrefs = platform.getProgrammer(programmer);
|
||||
} else {
|
||||
programmerPrefs = targetPlatform.getProgrammer(programmer);
|
||||
}
|
||||
if (programmerPrefs == null)
|
||||
throw new RunnerException(
|
||||
_("Please select a programmer from Tools->Programmer menu"));
|
||||
|
||||
// Build configuration for the current programmer
|
||||
PreferencesMap prefs = PreferencesData.getMap();
|
||||
prefs.putAll(BaseNoGui.getBoardPreferences());
|
||||
prefs.putAll(programmerPrefs);
|
||||
|
||||
// Create configuration for bootloader tool
|
||||
PreferencesMap toolPrefs = new PreferencesMap();
|
||||
String tool = prefs.getOrExcept("bootloader.tool");
|
||||
if (tool.contains(":")) {
|
||||
String[] split = tool.split(":", 2);
|
||||
TargetPlatform platform = BaseNoGui.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.getOrExcept("erase.params.verbose"));
|
||||
prefs.put("bootloader.verbose", prefs.getOrExcept("bootloader.params.verbose"));
|
||||
} else {
|
||||
prefs.put("erase.verbose", prefs.getOrExcept("erase.params.quiet"));
|
||||
prefs.put("bootloader.verbose", prefs.getOrExcept("bootloader.params.quiet"));
|
||||
}
|
||||
|
||||
try {
|
||||
String pattern = prefs.getOrExcept("erase.pattern");
|
||||
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
if (!executeUploadCommand(cmd))
|
||||
return false;
|
||||
|
||||
pattern = prefs.getOrExcept("bootloader.pattern");
|
||||
cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
|
||||
return executeUploadCommand(cmd);
|
||||
} catch (RunnerException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RunnerException(e);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user