diff --git a/app/.classpath b/app/.classpath
index f32ff129bf7..374fca9f467 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -38,7 +38,7 @@
-
+
diff --git a/app/lib/jmdns-3.4.1.jar b/app/lib/jmdns-3.4.1.jar
deleted file mode 100644
index 4fcd002b4b5..00000000000
Binary files a/app/lib/jmdns-3.4.1.jar and /dev/null differ
diff --git a/app/lib/jmdns-3.4.2.jar b/app/lib/jmdns-3.4.2.jar
new file mode 100644
index 00000000000..3112053f297
Binary files /dev/null and b/app/lib/jmdns-3.4.2.jar differ
diff --git a/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java b/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java
index 112296b43b8..4cc377ea903 100644
--- a/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java
+++ b/app/src/cc/arduino/UpdatableBoardsLibsFakeURLsHandler.java
@@ -53,22 +53,28 @@ public void hyperlinkUpdate(HyperlinkEvent event) {
}
URL url = event.getURL();
+ openBoardLibManager(url);
+ }
+ public void openBoardLibManager(URL url) {
if (BOARDSMANAGER.equals(url.getHost())) {
try {
- base.openBoardsManager("", "DropdownUpdatableCoresItem");
+ base.openBoardsManager(url.getRef() == null ? "": url.getRef() , url.getPath() == null ? "" : url.getPath().replace("/", ""));
} catch (Exception e) {
e.printStackTrace();
}
return;
}
+ System.out.println(url.getRef() + " " + url.getHost() + " " + url.getPath());
+
if (LIBRARYMANAGER.equals(url.getHost())) {
- base.openLibraryManager("DropdownUpdatableLibrariesItem");
+ base.openLibraryManager(url.getRef() == null ? "": url.getRef() , url.getPath() == null ? "" : url.getPath().replace("/", ""));
return;
}
throw new IllegalArgumentException(url.getHost() + " is invalid");
+
}
}
diff --git a/app/src/cc/arduino/contributions/ContributionsSelfCheck.java b/app/src/cc/arduino/contributions/ContributionsSelfCheck.java
index 1031effc3e5..636319d29b4 100644
--- a/app/src/cc/arduino/contributions/ContributionsSelfCheck.java
+++ b/app/src/cc/arduino/contributions/ContributionsSelfCheck.java
@@ -83,9 +83,9 @@ public void run() {
String text;
if (updatableLibraries > 0 && updatablePlatforms <= 0) {
- text = I18n.format(tr("Updates available for some of your {0}libraries{1}"), "", "");
+ text = I18n.format(tr("Updates available for some of your {0}libraries{1}"), "", "");
} else if (updatableLibraries <= 0 && updatablePlatforms > 0) {
- text = I18n.format(tr("Updates available for some of your {0}boards{1}"), "", "");
+ text = I18n.format(tr("Updates available for some of your {0}boards{1}"), "", "");
} else {
text = I18n.format(tr("Updates available for some of your {0}boards{1} and {2}libraries{3}"), "", "", "", "");
}
diff --git a/app/src/cc/arduino/contributions/libraries/filters/UpdatableLibraryPredicate.java b/app/src/cc/arduino/contributions/libraries/filters/UpdatableLibraryPredicate.java
index 32165643b4a..821d14ce2ab 100644
--- a/app/src/cc/arduino/contributions/libraries/filters/UpdatableLibraryPredicate.java
+++ b/app/src/cc/arduino/contributions/libraries/filters/UpdatableLibraryPredicate.java
@@ -54,7 +54,8 @@ public boolean test(ContributedLibrary contributedLibrary) {
}
List libraries = BaseNoGui.librariesIndexer.getIndex().find(libraryName);
return libraries.stream()
- .filter(library -> versionComparator.greaterThan(library.getParsedVersion(), installed.getParsedVersion()))
+ .filter(library -> versionComparator.greaterThan(library.getParsedVersion(), installed.getParsedVersion())
+ && library.getArchitectures().containsAll(installed.getArchitectures()))
.count() > 0;
}
}
diff --git a/app/src/cc/arduino/view/NotificationPopup.java b/app/src/cc/arduino/view/NotificationPopup.java
index f5dfc717e9d..7ddbf2c3f3e 100644
--- a/app/src/cc/arduino/view/NotificationPopup.java
+++ b/app/src/cc/arduino/view/NotificationPopup.java
@@ -61,7 +61,7 @@ public NotificationPopup(Frame parent, HyperlinkListener hyperlinkListener,
super(parent, false);
setLayout(new FlowLayout());
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
- setAlwaysOnTop(true);
+ //setAlwaysOnTop(true);
setUndecorated(true);
setResizable(false);
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 832973fe1ad..7f9906dad72 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -1135,7 +1135,7 @@ public void rebuildImportMenu(JMenu importMenu) {
importMenu.removeAll();
JMenuItem menu = new JMenuItem(tr("Manage Libraries..."));
- menu.addActionListener(e -> openLibraryManager(""));
+ menu.addActionListener(e -> openLibraryManager("", ""));
importMenu.add(menu);
importMenu.addSeparator();
@@ -1264,7 +1264,7 @@ public void onBoardOrPortChange() {
}
}
- public void openLibraryManager(String dropdownItem) {
+ public void openLibraryManager(final String filterText, String dropdownItem) {
if (contributionsSelfCheck != null) {
contributionsSelfCheck.cancel();
}
@@ -1280,6 +1280,9 @@ protected void onIndexesUpdated() throws Exception {
if (StringUtils.isNotEmpty(dropdownItem)) {
selectDropdownItemByClassName(dropdownItem);
}
+ if (StringUtils.isNotEmpty(filterText)) {
+ setFilterText(filterText);
+ }
}
};
managerUI.setLocationRelativeTo(activeEditor);
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 566cabf1c3f..d018b69b278 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -29,6 +29,7 @@
import cc.arduino.view.GoToLineNumber;
import cc.arduino.view.StubMenuListener;
import cc.arduino.view.findreplace.FindReplace;
+import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
import com.jcraft.jsch.JSchException;
import jssc.SerialPortException;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
@@ -145,6 +146,8 @@ public boolean test(Sketch sketch) {
private int numTools = 0;
+ public boolean avoidMultipleOperations = false;
+
private final EditorToolbar toolbar;
// these menus are shared so that they needn't be rebuilt for all windows
// each time a sketch is created, renamed, or moved.
@@ -197,7 +200,7 @@ public boolean test(Sketch sketch) {
private Runnable stopHandler;
Runnable exportHandler;
private Runnable exportAppHandler;
-
+ private Runnable timeoutUploadHandler;
public Editor(Base ibase, File file, int[] storedLocation, int[] defaultLocation, Platform platform) throws Exception {
super("Arduino");
@@ -811,6 +814,9 @@ public void actionPerformed(ActionEvent e) {
portMenu = new JMenu(tr("Port"));
populatePortMenu();
toolsMenu.add(portMenu);
+ item = new JMenuItem(tr("Get Board Info"));
+ item.addActionListener(e -> handleBoardInfo());
+ toolsMenu.add(item);
toolsMenu.addSeparator();
base.rebuildProgrammerMenu();
@@ -1015,9 +1021,15 @@ private SketchTextArea createTextArea() throws IOException {
textArea.setTabSize(PreferencesData.getInteger("editor.tabs.size"));
textArea.addHyperlinkListener(evt -> {
try {
- platform.openURL(sketch.getFolder(), evt.getURL().toExternalForm());
- } catch (Exception e) {
- Base.showWarning(e.getMessage(), e.getMessage(), e);
+ UpdatableBoardsLibsFakeURLsHandler boardLibHandler = new UpdatableBoardsLibsFakeURLsHandler(base);
+ boardLibHandler.openBoardLibManager(evt.getURL());
+ }
+ catch (Exception e) {
+ try {
+ platform.openURL(sketch.getFolder(), evt.getURL().toExternalForm());
+ } catch (Exception f) {
+ Base.showWarning(f.getMessage(), f.getMessage(), f);
+ }
}
});
textArea.addCaretListener(e -> {
@@ -1641,6 +1653,7 @@ private void resetHandlers() {
stopHandler = new DefaultStopHandler();
exportHandler = new DefaultExportHandler();
exportAppHandler = new DefaultExportAppHandler();
+ timeoutUploadHandler = new TimeoutUploadHandler();
}
@@ -1972,6 +1985,7 @@ public void run() {
status.unprogress();
toolbar.deactivateRun();
+ avoidMultipleOperations = false;
}
}
@@ -2360,6 +2374,7 @@ synchronized public void handleExport(final boolean usingProgrammer) {
console.clear();
status.progress(tr("Uploading to I/O Board..."));
+ new Thread(timeoutUploadHandler).start();
new Thread(usingProgrammer ? exportAppHandler : exportHandler).start();
}
@@ -2399,6 +2414,7 @@ public void run() {
e.printStackTrace();
} finally {
populatePortMenu();
+ avoidMultipleOperations = false;
}
status.unprogress();
uploading = false;
@@ -2426,13 +2442,14 @@ private void resumeOrCloseSerialMonitor() {
}
}
try {
- if (serialMonitor != null)
- serialMonitor.resume(boardPort);
- if (boardPort == null) {
- serialMonitor.close();
- handleSerial();
- } else {
+ if (serialMonitor != null) {
serialMonitor.resume(boardPort);
+ if (boardPort == null) {
+ serialMonitor.close();
+ handleSerial();
+ } else {
+ serialMonitor.resume(boardPort);
+ }
}
} catch (Exception e) {
statusError(e);
@@ -2493,6 +2510,7 @@ public void run() {
} catch (Exception e) {
e.printStackTrace();
} finally {
+ avoidMultipleOperations = false;
populatePortMenu();
}
status.unprogress();
@@ -2507,6 +2525,20 @@ public void run() {
}
}
+ class TimeoutUploadHandler implements Runnable {
+
+ public void run() {
+ try {
+ //10 seconds, than reactivate upload functionality and let the programmer pid being killed
+ Thread.sleep(1000 * 10);
+ if (uploading) {
+ avoidMultipleOperations = false;
+ }
+ } catch (InterruptedException e) {
+ // noop
+ }
+ }
+ }
public void handleSerial() {
if(serialPlotter != null) {
@@ -2547,11 +2579,11 @@ public void handleSerial() {
}
serialMonitor = new MonitorFactory().newMonitor(port);
- serialMonitor.setIconImage(getIconImage());
+ base.setIcon(serialMonitor);
// If currently uploading, disable the monitor (it will be later
// enabled when done uploading)
- if (uploading) {
+ if (uploading || avoidMultipleOperations) {
try {
serialMonitor.suspend();
} catch (Exception e) {
@@ -2575,8 +2607,10 @@ public void handleSerial() {
}
try {
- serialMonitor.open();
serialMonitor.setVisible(true);
+ if (!avoidMultipleOperations) {
+ serialMonitor.open();
+ }
success = true;
} catch (ConnectException e) {
statusError(tr("Unable to connect: is the sketch using the bridge?"));
@@ -2643,7 +2677,7 @@ public void handlePlotter() {
}
serialPlotter = new SerialPlotter(port);
- serialPlotter.setIconImage(getIconImage());
+ base.setIcon(serialPlotter);
// If currently uploading, disable the plotter (it will be later
// enabled when done uploading)
@@ -2723,6 +2757,59 @@ private void handleBurnBootloader() {
}).start();
}
+ private void handleBoardInfo() {
+ console.clear();
+
+ String selectedPort = PreferencesData.get("serial.port");
+ List ports = Base.getDiscoveryManager().discovery();
+
+ String label = "";
+ String vid = "";
+ String pid = "";
+ String iserial = "";
+ String protocol = "";
+ boolean found = false;
+
+ for (BoardPort port : ports) {
+ if (port.getAddress().equals(selectedPort)) {
+ label = port.getBoardName();
+ vid = port.getVID();
+ pid = port.getPID();
+ iserial = port.getISerial();
+ protocol = port.getProtocol();
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ statusNotice(tr("Please select a port to obtain board info"));
+ return;
+ }
+
+ if (protocol.equals("network")) {
+ statusNotice(tr("Network port, can't obtain info"));
+ return;
+ }
+
+ if (vid == null || vid.equals("") || vid.equals("0000")) {
+ statusNotice(tr("Native serial port, can't obtain info"));
+ return;
+ }
+
+ if (iserial == null || iserial.equals("")) {
+ iserial = tr("Upload any sketch to obtain it");
+ }
+
+ if (label == null) {
+ label = tr("Unknown board");
+ }
+
+ String infos = I18n.format("BN: {0}\nVID: {1}\nPID: {2}\nSN: {3}", label, vid, pid, iserial);
+ JTextArea textArea = new JTextArea(infos);
+
+ JOptionPane.showMessageDialog(this, textArea, tr("Board Info"), JOptionPane.PLAIN_MESSAGE);
+ }
/**
* Handler for File → Page Setup.
diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java
index b68b74b4674..506e8f56d71 100644
--- a/app/src/processing/app/EditorLineStatus.java
+++ b/app/src/processing/app/EditorLineStatus.java
@@ -52,6 +52,7 @@ public class EditorLineStatus extends JComponent {
String text = "";
String name = "";
String serialport = "";
+ String serialnumber = "";
public EditorLineStatus() {
background = Theme.getColor("linestatus.bgcolor");
@@ -129,6 +130,10 @@ public void setSerialPort(String serialport) {
this.serialport = serialport;
}
+ public void setSerialNumber(String serialnumber) {
+ this.serialnumber = serialnumber;
+ }
+
public Dimension getPreferredSize() {
return scale(new Dimension(300, height));
}
diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java
index a6b8bce6047..a4d18b5f72d 100644
--- a/app/src/processing/app/EditorToolbar.java
+++ b/app/src/processing/app/EditorToolbar.java
@@ -341,7 +341,10 @@ public void mousePressed(MouseEvent e) {
switch (sel) {
case RUN:
- editor.handleRun(false, editor.presentHandler, editor.runHandler);
+ if (!editor.avoidMultipleOperations) {
+ editor.handleRun(false, editor.presentHandler, editor.runHandler);
+ editor.avoidMultipleOperations = true;
+ }
break;
// case STOP:
@@ -370,7 +373,11 @@ public void mousePressed(MouseEvent e) {
break;
case EXPORT:
- editor.handleExport(e.isShiftDown());
+ // launch a timeout timer which can reenable to upload button functionality an
+ if (!editor.avoidMultipleOperations) {
+ editor.handleExport(e.isShiftDown());
+ editor.avoidMultipleOperations = true;
+ }
break;
case SERIAL:
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
index ecbd54938a6..7bb7dee11e6 100644
--- a/app/src/processing/app/Sketch.java
+++ b/app/src/processing/app/Sketch.java
@@ -1164,7 +1164,8 @@ private boolean exportApplet(String appletPath, boolean usingProgrammer)
private boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception {
- Uploader uploader = new UploaderUtils().getUploaderByPreferences(false);
+ UploaderUtils uploaderInstance = new UploaderUtils();
+ Uploader uploader = uploaderInstance.getUploaderByPreferences(false);
boolean success = false;
do {
@@ -1183,7 +1184,7 @@ private boolean upload(String buildPath, String suggestedClassName, boolean usin
List warningsAccumulator = new LinkedList<>();
try {
- success = new UploaderUtils().upload(data, uploader, buildPath, suggestedClassName, usingProgrammer, false, warningsAccumulator);
+ success = uploaderInstance.upload(data, uploader, buildPath, suggestedClassName, usingProgrammer, false, warningsAccumulator);
} finally {
if (uploader.requiresAuthorization() && !success) {
PreferencesData.remove(uploader.getAuthorizationKey());
@@ -1198,6 +1199,14 @@ private boolean upload(String buildPath, String suggestedClassName, boolean usin
} while (uploader.requiresAuthorization() && !success);
+ if (!success) {
+ String errorMessage = uploader.getFailureMessage();
+ if (errorMessage.equals("")) {
+ errorMessage = tr("An error occurred while uploading the sketch");
+ }
+ editor.statusError(errorMessage);
+ }
+
return success;
}
diff --git a/arduino-core/.classpath b/arduino-core/.classpath
index cf3a2da06c2..93dbc9f5cb4 100644
--- a/arduino-core/.classpath
+++ b/arduino-core/.classpath
@@ -5,7 +5,7 @@
-
+
diff --git a/arduino-core/lib/jmdns-3.4.1.jar b/arduino-core/lib/jmdns-3.4.1.jar
deleted file mode 100644
index 4fcd002b4b5..00000000000
Binary files a/arduino-core/lib/jmdns-3.4.1.jar and /dev/null differ
diff --git a/arduino-core/lib/jmdns-3.4.2.jar b/arduino-core/lib/jmdns-3.4.2.jar
new file mode 100644
index 00000000000..3112053f297
Binary files /dev/null and b/arduino-core/lib/jmdns-3.4.2.jar differ
diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java
index 1063b676a32..52305e66468 100644
--- a/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java
+++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java
@@ -80,6 +80,7 @@ public void resolveToolsDependencies(Collection packages) {
if (tool == null) {
System.err.println("Index error: could not find referenced tool " + dep);
} else {
+ tool.usetUserArchitecture(this.getParentPackage().getName()+"."+this.getArchitecture());
resolvedToolReferences.put(dep, tool);
}
}
diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java
index 28d81771722..370177f0dd9 100644
--- a/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java
+++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java
@@ -32,6 +32,7 @@
import cc.arduino.contributions.DownloadableContribution;
import processing.app.Platform;
+import java.util.LinkedList;
import java.util.List;
public abstract class ContributedTool {
@@ -42,6 +43,20 @@ public abstract class ContributedTool {
public abstract List getSystems();
+ private LinkedList users = null;
+ public void usetUserArchitecture(String vendorAndArch) {
+ if (users == null) {
+ users = new LinkedList<>();
+ }
+ if (!users.contains(vendorAndArch)) {
+ users.add(vendorAndArch);
+ }
+ }
+
+ public List ugetUserArchitectures() {
+ return users;
+ }
+
public DownloadableContribution getDownloadableContribution(Platform platform) {
for (HostDependentDownloadableContribution c : getSystems()) {
if (c.isCompatible(platform))
diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java
index e2c16c43e69..0e85ffe135d 100644
--- a/arduino-core/src/cc/arduino/packages/BoardPort.java
+++ b/arduino-core/src/cc/arduino/packages/BoardPort.java
@@ -36,8 +36,12 @@ public class BoardPort {
private String address;
private String protocol;
private String boardName;
+ private String vid;
+ private String pid;
+ private String iserial;
private String label;
private final PreferencesMap prefs;
+ private boolean online;
public BoardPort() {
this.prefs = new PreferencesMap();
@@ -79,4 +83,36 @@ public String getLabel() {
return label;
}
+ public void setOnlineStatus(boolean online) {
+ this.online = online;
+ }
+
+ public boolean isOnline() {
+ return online;
+ }
+
+ public void setVIDPID(String vid, String pid) {
+ this.vid = vid;
+ this.pid = pid;
+ }
+
+ public String getVID() {
+ return vid;
+ }
+
+ public String getPID() {
+ return pid;
+ }
+
+ public void setISerial(String iserial) {
+ this.iserial = iserial;
+ }
+ public String getISerial() {
+ return iserial;
+ }
+
+ @Override
+ public String toString() {
+ return this.address+"_"+this.vid+"_"+this.pid;
+ }
}
diff --git a/arduino-core/src/cc/arduino/packages/Discovery.java b/arduino-core/src/cc/arduino/packages/Discovery.java
index eb4b41da2b1..911fcc2f6f5 100644
--- a/arduino-core/src/cc/arduino/packages/Discovery.java
+++ b/arduino-core/src/cc/arduino/packages/Discovery.java
@@ -51,5 +51,6 @@ public interface Discovery {
* @return
*/
List listDiscoveredBoards();
+ List listDiscoveredBoards(boolean complete);
}
diff --git a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java
index add7d0671e6..2632386d47e 100644
--- a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java
+++ b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java
@@ -40,11 +40,13 @@
public class DiscoveryManager {
private final List discoverers;
+ private final SerialDiscovery serialDiscoverer = new SerialDiscovery();
+ private final NetworkDiscovery networkDiscoverer = new NetworkDiscovery();
public DiscoveryManager() {
discoverers = new ArrayList();
- discoverers.add(new SerialDiscovery());
- discoverers.add(new NetworkDiscovery());
+ discoverers.add(serialDiscoverer);
+ discoverers.add(networkDiscoverer);
// Start all discoverers
for (Discovery d : discoverers) {
@@ -69,6 +71,10 @@ public DiscoveryManager() {
Runtime.getRuntime().addShutdownHook(closeHook);
}
+ public SerialDiscovery getSerialDiscoverer() {
+ return serialDiscoverer;
+ }
+
public List discovery() {
List res = new ArrayList();
for (Discovery d : discoverers) {
@@ -77,6 +83,14 @@ public List discovery() {
return res;
}
+ public List discovery(boolean complete) {
+ List res = new ArrayList();
+ for (Discovery d : discoverers) {
+ res.addAll(d.listDiscoveredBoards(complete));
+ }
+ return res;
+ }
+
public BoardPort find(String address) {
for (BoardPort boardPort : discovery()) {
if (boardPort.getAddress().equals(address)) {
@@ -86,4 +100,13 @@ public BoardPort find(String address) {
return null;
}
+ public BoardPort find(String address, boolean complete) {
+ for (BoardPort boardPort : discovery(complete)) {
+ if (boardPort.getAddress().equals(address)) {
+ return boardPort;
+ }
+ }
+ return null;
+ }
+
}
diff --git a/arduino-core/src/cc/arduino/packages/Uploader.java b/arduino-core/src/cc/arduino/packages/Uploader.java
index d58d29504f5..28a0ed4427c 100644
--- a/arduino-core/src/cc/arduino/packages/Uploader.java
+++ b/arduino-core/src/cc/arduino/packages/Uploader.java
@@ -44,6 +44,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import static processing.app.I18n.tr;
@@ -85,7 +86,7 @@ protected Uploader(boolean nup) {
}
private void init(boolean nup) {
- this.error = null;
+ this.error = "";
this.notFoundError = false;
this.noUploadPort = nup;
}
@@ -102,6 +103,9 @@ public String getAuthorizationKey() {
return null;
}
+ // static field for last executed programmer process ID
+ static protected Process programmerPid;
+
protected boolean executeUploadCommand(Collection command) throws Exception {
return executeUploadCommand(command.toArray(new String[command.size()]));
}
@@ -121,24 +125,31 @@ protected boolean executeUploadCommand(String command[]) throws Exception {
System.out.println();
}
Process process = ProcessUtils.exec(command);
+ programmerPid = process;
new MessageSiphon(process.getInputStream(), this, 100);
new MessageSiphon(process.getErrorStream(), this, 100);
- // wait for the process to finish.
- result = process.waitFor();
+ // wait for the process to finish, but not forever
+ // kill the flasher process after 2 minutes to avoid 100% cpu spinning
+ if (!process.waitFor(2, TimeUnit.MINUTES)) {
+ process.destroyForcibly();
+ }
+ if (!process.isAlive()) {
+ result = process.exitValue();
+ } else {
+ result = 0;
+ }
} catch (Exception e) {
e.printStackTrace();
}
- if (error != null) {
- RunnerException exception = new RunnerException(error);
- exception.hideStackTrace();
- throw exception;
- }
-
return result == 0;
}
+ public String getFailureMessage() {
+ return error;
+ }
+
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)) {
@@ -148,8 +159,9 @@ public void message(String s) {
System.err.print(s);
// ignore cautions
- if (s.contains("Error")) {
+ if (s.toLowerCase().contains("error")) {
notFoundError = true;
+ error = s;
return;
}
if (notFoundError) {
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java
index ebbb8c50df1..6fb15b24d82 100644
--- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java
+++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java
@@ -31,82 +31,38 @@
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Discovery;
-import cc.arduino.packages.discoverers.network.BoardReachabilityFilter;
-import cc.arduino.packages.discoverers.network.NetworkChecker;
-import org.apache.commons.compress.utils.IOUtils;
import processing.app.BaseNoGui;
-import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter;
import javax.jmdns.*;
-import javax.jmdns.impl.DNSTaskStarter;
import java.io.IOException;
import java.net.InetAddress;
import java.util.*;
-public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.packages.discoverers.network.NetworkTopologyListener {
-
- private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000;
-
- private final List boardPortsDiscoveredWithJmDNS;
- private final Map mappedJmDNSs;
- private Timer networkCheckerTimer;
- private Timer boardReachabilityFilterTimer;
- private final List reachableBoardPorts;
+import cc.arduino.packages.discoverers.network.BoardReachabilityFilter;
- public NetworkDiscovery() {
- DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter());
- this.boardPortsDiscoveredWithJmDNS = new LinkedList<>();
- this.mappedJmDNSs = new Hashtable<>();
- this.reachableBoardPorts = new LinkedList<>();
- }
+public class NetworkDiscovery implements Discovery, ServiceListener {
- @Override
- public List listDiscoveredBoards() {
- synchronized (reachableBoardPorts) {
- return new LinkedList<>(reachableBoardPorts);
- }
- }
+ private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000;
- public void setReachableBoardPorts(List newReachableBoardPorts) {
- synchronized (reachableBoardPorts) {
- this.reachableBoardPorts.clear();
- this.reachableBoardPorts.addAll(newReachableBoardPorts);
- }
- }
+ private final List reachableBoardPorts = new LinkedList<>();
+ private final List boardPortsDiscoveredWithJmDNS = new LinkedList<>();
+ private Timer reachabilityTimer;
+ private JmDNS jmdns = null;
- public List getBoardPortsDiscoveredWithJmDNS() {
+ private void removeDuplicateBoards(BoardPort newBoard) {
synchronized (boardPortsDiscoveredWithJmDNS) {
- return new LinkedList<>(boardPortsDiscoveredWithJmDNS);
+ Iterator iterator = boardPortsDiscoveredWithJmDNS.iterator();
+ while (iterator.hasNext()) {
+ BoardPort board = iterator.next();
+ if (newBoard.getAddress().equals(board.getAddress())) {
+ iterator.remove();
+ }
+ }
}
}
- @Override
- public void start() throws IOException {
- this.networkCheckerTimer = new Timer(NetworkChecker.class.getName());
- new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(networkCheckerTimer);
- this.boardReachabilityFilterTimer = new Timer(BoardReachabilityFilter.class.getName());
- new BoardReachabilityFilter(this).start(boardReachabilityFilterTimer);
- }
-
- @Override
- public void stop() throws IOException {
- this.networkCheckerTimer.purge();
- this.boardReachabilityFilterTimer.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
@@ -119,11 +75,9 @@ public void serviceRemoved(ServiceEvent serviceEvent) {
@Override
public void serviceResolved(ServiceEvent serviceEvent) {
- int sleptFor = 0;
- while (BaseNoGui.packages == null && sleptFor <= MAX_TIME_AWAITING_FOR_PACKAGES) {
+ while (BaseNoGui.packages == null) {
try {
Thread.sleep(1000);
- sleptFor += 1000;
} catch (InterruptedException e) {
e.printStackTrace();
}
@@ -144,7 +98,7 @@ public void serviceResolved(ServiceEvent serviceEvent) {
port.getPrefs().put("board", board);
port.getPrefs().put("distro_version", info.getPropertyString("distro_version"));
port.getPrefs().put("port", "" + info.getPort());
-
+
//Add additional fields to permit generic ota updates
//and make sure we do not intefere with Arduino boards
// define "ssh_upload=no" TXT property to use generic uploader
@@ -183,35 +137,58 @@ public void serviceResolved(ServiceEvent serviceEvent) {
}
}
- private void removeDuplicateBoards(BoardPort newBoard) {
- synchronized (boardPortsDiscoveredWithJmDNS) {
- Iterator iterator = boardPortsDiscoveredWithJmDNS.iterator();
- while (iterator.hasNext()) {
- BoardPort board = iterator.next();
- if (newBoard.getAddress().equals(board.getAddress())) {
- iterator.remove();
- }
- }
- }
+ public NetworkDiscovery() {
+
}
@Override
- public void inetAddressAdded(InetAddress address) {
- if (mappedJmDNSs.containsKey(address)) {
- return;
+ public void start() {
+ try {
+ jmdns = JmDNS.create();
+ jmdns.addServiceListener("_arduino._tcp.local.", this);
+ } catch (IOException e) {
+ e.printStackTrace();
}
+ reachabilityTimer = new Timer();
+ new BoardReachabilityFilter(this).start(reachabilityTimer);
+ }
+
+ @Override
+ public void stop() {
+ jmdns.unregisterAllServices();
try {
- JmDNS jmDNS = JmDNS.create(address);
- jmDNS.addServiceListener("_arduino._tcp.local.", this);
- mappedJmDNSs.put(address, jmDNS);
- } catch (Exception e) {
+ jmdns.close();
+ } catch (IOException e) {
e.printStackTrace();
}
+ reachabilityTimer.cancel();
+ start();
+ }
+
+ @Override
+ public List listDiscoveredBoards() {
+ synchronized (reachableBoardPorts) {
+ return new LinkedList<>(reachableBoardPorts);
+ }
}
@Override
- public void inetAddressRemoved(InetAddress address) {
- JmDNS jmDNS = mappedJmDNSs.remove(address);
- IOUtils.closeQuietly(jmDNS);
+ public List listDiscoveredBoards(boolean complete) {
+ synchronized (reachableBoardPorts) {
+ return new LinkedList<>(reachableBoardPorts);
+ }
+ }
+
+ public void setReachableBoardPorts(List newReachableBoardPorts) {
+ synchronized (reachableBoardPorts) {
+ this.reachableBoardPorts.clear();
+ this.reachableBoardPorts.addAll(newReachableBoardPorts);
+ }
+ }
+
+ public List getBoardPortsDiscoveredWithJmDNS() {
+ synchronized (boardPortsDiscoveredWithJmDNS) {
+ return new LinkedList<>(boardPortsDiscoveredWithJmDNS);
+ }
}
}
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java
index 9c3efdc5200..3e6646d6732 100644
--- a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java
+++ b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java
@@ -41,6 +41,7 @@ public class SerialDiscovery implements Discovery {
private Timer serialBoardsListerTimer;
private final List serialBoardPorts;
+ private SerialBoardsLister serialBoardsLister = new SerialBoardsLister(this);;
public SerialDiscovery() {
this.serialBoardPorts = new LinkedList<>();
@@ -48,26 +49,45 @@ public SerialDiscovery() {
@Override
public List listDiscoveredBoards() {
- return getSerialBoardPorts();
+ return getSerialBoardPorts(false);
}
- private List getSerialBoardPorts() {
- synchronized (serialBoardPorts) {
- return new LinkedList<>(serialBoardPorts);
- }
+ public List listDiscoveredBoards(boolean complete) {
+ return getSerialBoardPorts(complete);
+ }
+
+ private List getSerialBoardPorts(boolean complete) {
+ if (complete) {
+ return new LinkedList<>(serialBoardPorts);
+ }
+ List onlineBoardPorts = new LinkedList<>();
+ for (BoardPort port : serialBoardPorts) {
+ if (port.isOnline() == true) {
+ onlineBoardPorts.add(port);
+ }
+ }
+ return onlineBoardPorts;
}
public void setSerialBoardPorts(List newSerialBoardPorts) {
- synchronized (serialBoardPorts) {
serialBoardPorts.clear();
serialBoardPorts.addAll(newSerialBoardPorts);
- }
}
+ public void forceRefresh() {
+ serialBoardsLister.retriggerDiscovery(false);
+ }
+
+ public void setUploadInProgress(boolean param) {
+ serialBoardsLister.uploadInProgress = param;
+ }
+
+ public void pausePolling(boolean param) { serialBoardsLister.pausePolling = param;}
+
@Override
public void start() {
this.serialBoardsListerTimer = new Timer(SerialBoardsLister.class.getName());
- new SerialBoardsLister(this).start(serialBoardsListerTimer);
+ serialBoardsLister.start(serialBoardsListerTimer);
}
@Override
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java b/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java
index 433142eb3b9..d4158be4795 100644
--- a/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java
+++ b/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java
@@ -34,23 +34,51 @@
import processing.app.helpers.NetUtils;
import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Enumeration;
import java.net.UnknownHostException;
import java.util.*;
public class BoardReachabilityFilter extends TimerTask {
private final NetworkDiscovery networkDiscovery;
+ private Enumeration staticNetworkInterfaces;
+ private final List staticNetworkInterfacesList = new LinkedList<>();
public BoardReachabilityFilter(NetworkDiscovery networkDiscovery) {
this.networkDiscovery = networkDiscovery;
}
public void start(Timer timer) {
- timer.schedule(this, 0, 3000);
+ try {
+ staticNetworkInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (staticNetworkInterfaces.hasMoreElements()) {
+ staticNetworkInterfacesList.add(staticNetworkInterfaces.nextElement().getInterfaceAddresses().toString());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ timer.schedule(this, 0, 5000);
}
@Override
public void run() {
+
+ try {
+ Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (networkInterfaces.hasMoreElements()) {
+ if (!staticNetworkInterfacesList.contains(networkInterfaces.nextElement().getInterfaceAddresses().toString())) {
+ networkDiscovery.stop();
+ staticNetworkInterfacesList.clear();
+ System.out.println("IP changed, restarting jmdns");
+ return;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
List boardPorts = networkDiscovery.getBoardPortsDiscoveredWithJmDNS();
Iterator boardPortIterator = boardPorts.iterator();
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkChecker.java b/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkChecker.java
deleted file mode 100644
index df58c220d0a..00000000000
--- a/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkChecker.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.*;
-
-public class NetworkChecker extends TimerTask {
-
- private final NetworkTopologyListener topologyListener;
- private final NetworkTopologyDiscovery topology;
-
- private Set knownAddresses;
-
- public NetworkChecker(NetworkTopologyListener topologyListener, NetworkTopologyDiscovery topology) {
- super();
- this.topologyListener = topologyListener;
- this.topology = topology;
- this.knownAddresses = Collections.synchronizedSet(new HashSet<>());
- }
-
- public void start(Timer timer) {
- timer.schedule(this, 0, 3000);
- }
-
- @Override
- public void run() {
- if (!hasNetworkInterfaces()) {
- return;
- }
- try {
- InetAddress[] curentAddresses = topology.getInetAddresses();
- Set current = new HashSet<>(curentAddresses.length);
- for (InetAddress address : curentAddresses) {
- current.add(address);
- if (!knownAddresses.contains(address)) {
- topologyListener.inetAddressAdded(address);
- }
- }
- knownAddresses.stream().filter(address -> !current.contains(address)).forEach(topologyListener::inetAddressRemoved);
- knownAddresses = current;
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private boolean hasNetworkInterfaces() {
- try {
- return NetworkInterface.getNetworkInterfaces() != null;
- } catch (SocketException e) {
- return false;
- }
- }
-}
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkTopologyListener.java b/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkTopologyListener.java
deleted file mode 100644
index f963baa6c5b..00000000000
--- a/arduino-core/src/cc/arduino/packages/discoverers/network/NetworkTopologyListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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);
-
-}
diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java
index 5ca99819b89..5bd10773ece 100644
--- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java
+++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java
@@ -31,62 +31,120 @@
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.discoverers.SerialDiscovery;
+import cc.arduino.packages.uploaders.SerialUploader;
import processing.app.BaseNoGui;
import processing.app.Platform;
-import processing.app.Serial;
import processing.app.debug.TargetBoard;
import java.util.*;
+import static processing.app.helpers.OSUtils.isWindows;
+
public class SerialBoardsLister extends TimerTask {
private final SerialDiscovery serialDiscovery;
+ private final List boardPorts = new LinkedList<>();
+ private List oldPorts = new LinkedList<>();
+ public boolean uploadInProgress = false;
+ public boolean pausePolling = false;
+ private BoardPort oldUploadBoardPort = null;
public SerialBoardsLister(SerialDiscovery serialDiscovery) {
this.serialDiscovery = serialDiscovery;
}
public void start(Timer timer) {
- timer.schedule(this, 0, 1000);
- }
- @Override
- public void run() {
- while (BaseNoGui.packages == null) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // noop
- }
+ if (isWindows()) {
+ timer.schedule(this, 0, 3000);
+ } else {
+ timer.schedule(this, 0, 1000);
}
+ }
+ public synchronized void retriggerDiscovery(boolean polled) {
Platform platform = BaseNoGui.getPlatform();
if (platform == null) {
return;
}
- List boardPorts = new LinkedList<>();
+ if (polled && pausePolling) {
+ return;
+ }
+
+ List ports = platform.listSerials();
+ if (ports.equals(oldPorts)) {
+ return;
+ }
+
+ // if (updating) {}
+ // a port will disappear, another will appear
+ // use this information to "merge" the boards
+ // updating must be signaled by SerialUpload class
- List ports = Serial.list();
+ oldPorts.clear();
+ oldPorts.addAll(ports);
- String devicesListOutput = null;
- if (!ports.isEmpty()) {
- devicesListOutput = platform.preListAllCandidateDevices();
+ for (BoardPort board : boardPorts) {
+ if (ports.contains(board.toString())) {
+ if (board.isOnline()) {
+ ports.remove(ports.indexOf(board.toString()));
+ }
+ } else {
+ if (uploadInProgress && board.isOnline()) {
+ oldUploadBoardPort = board;
+ }
+ board.setOnlineStatus(false);
+ }
}
- for (String port : ports) {
- Map boardData = platform.resolveDeviceByVendorIdProductId(port, BaseNoGui.packages, devicesListOutput);
+ for (String newPort : ports) {
+
+ String[] parts = newPort.split("_");
+ String port = parts[0];
- BoardPort boardPort = new BoardPort();
+ if (parts.length != 3) {
+ // something went horribly wrong
+ continue;
+ }
+
+ Map boardData = platform.resolveDeviceByVendorIdProductId(port, BaseNoGui.packages);
+
+ BoardPort boardPort = null;
+ boolean updatingInfos = false;
+ int i = 0;
+ // create new board or update existing
+ for (BoardPort board : boardPorts) {
+ if (board.toString().equals(newPort)) {
+ updatingInfos = true;
+ boardPort = boardPorts.get(i);
+ break;
+ }
+ i++;
+ }
+ if (!updatingInfos) {
+ boardPort = new BoardPort();
+ }
boardPort.setAddress(port);
boardPort.setProtocol("serial");
+ boardPort.setOnlineStatus(true);
String label = port;
if (boardData != null) {
boardPort.getPrefs().put("vid", boardData.get("vid").toString());
boardPort.getPrefs().put("pid", boardData.get("pid").toString());
- boardPort.getPrefs().put("iserial", boardData.get("iserial").toString());
+ boardPort.setVIDPID(parts[1], parts[2]);
+
+ String iserial = boardData.get("iserial").toString();
+ if (iserial.length() >= 10) {
+ boardPort.getPrefs().put("iserial", iserial);
+ boardPort.setISerial(iserial);
+ }
+ if (uploadInProgress && oldUploadBoardPort!=null) {
+ oldUploadBoardPort.getPrefs().put("iserial", iserial);
+ oldUploadBoardPort.setISerial(iserial);
+ }
TargetBoard board = (TargetBoard) boardData.get("board");
if (board != null) {
@@ -96,13 +154,28 @@ public void run() {
}
boardPort.setBoardName(boardName);
}
+ } else {
+ if (parts[1] != "0000") {
+ boardPort.setVIDPID(parts[1], parts[2]);
+ } else {
+ boardPort.setVIDPID("0000", "0000");
+ boardPort.setISerial("");
+ }
}
boardPort.setLabel(label);
-
- boardPorts.add(boardPort);
+ if (!updatingInfos) {
+ boardPorts.add(boardPort);
+ }
}
-
serialDiscovery.setSerialBoardPorts(boardPorts);
}
+
+ @Override
+ public void run() {
+ if (BaseNoGui.packages == null) {
+ return;
+ }
+ retriggerDiscovery(true);
+ }
}
diff --git a/arduino-core/src/cc/arduino/packages/uploaders/GenericNetworkUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/GenericNetworkUploader.java
index 1bc5befe4b4..5e8c58934f3 100644
--- a/arduino-core/src/cc/arduino/packages/uploaders/GenericNetworkUploader.java
+++ b/arduino-core/src/cc/arduino/packages/uploaders/GenericNetworkUploader.java
@@ -93,7 +93,8 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
pattern = prefs.get("upload.network_pattern");
if(pattern == null)
pattern = prefs.getOrExcept("upload.pattern");
- String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ String arch = targetPlatform.getContainerPackage().getId()+"."+targetPlatform.getId();
+ String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
uploadResult = executeUploadCommand(cmd);
} catch (RunnerException e) {
throw e;
diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java
index b0ba1ec4ee9..cc0a1080827 100644
--- a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java
+++ b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java
@@ -135,7 +135,7 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
return runUploadTool(ssh, prefs);
} catch (JSchException e) {
String message = e.getMessage();
- if ("Auth cancel".equals(message) || "Auth fail".equals(message)) {
+ if (message.contains("Auth cancel") || message.contains("Auth fail") || message.contains("authentication fail")) {
return false;
}
if (e.getMessage().contains("Connection refused")) {
diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java
index 971bfb8c6f9..be8c784ef6d 100644
--- a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java
+++ b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java
@@ -44,6 +44,8 @@
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.StringReplacer;
+import cc.arduino.packages.discoverers.SerialDiscovery;
+
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -78,12 +80,19 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
}
prefs.putAll(targetPlatform.getTool(tool));
+ if (programmerPid != null && programmerPid.isAlive()) {
+ // kill the previous programmer
+ programmerPid.destroyForcibly();
+ }
+
// 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);
}
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(true);
+
if (noUploadPort)
{
prefs.put("build.path", buildPath);
@@ -96,10 +105,13 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
boolean uploadResult;
try {
String pattern = prefs.getOrExcept("upload.pattern");
- String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ String arch = targetPlatform.getContainerPackage().getId()+"."+targetPlatform.getId();
+ String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
uploadResult = executeUploadCommand(cmd);
} catch (Exception e) {
throw new RunnerException(e);
+ } finally {
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false);
}
return uploadResult;
}
@@ -134,13 +146,20 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
// 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.
+ // have already occurred before we start scanning.
actualUploadPort = waitForUploadPort(userSelectedUploadPort, before);
+
+ // on OS X, if the port is opened too quickly after it is detected,
+ // a "Resource busy" error occurs, add a delay to workaround this,
+ // apply to other platforms as well.
+ Thread.sleep(250);
}
} catch (SerialException e) {
throw new RunnerException(e);
} catch (InterruptedException e) {
throw new RunnerException(e.getMessage());
+ } finally {
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false);
}
if (actualUploadPort == null) {
actualUploadPort = userSelectedUploadPort;
@@ -151,13 +170,12 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
} else {
prefs.put("serial.port.file", actualUploadPort);
}
- }
- BoardPort boardPort = BaseNoGui.getDiscoveryManager().find(PreferencesData.get("serial.port"));
- try {
- prefs.put("serial.port.iserial", boardPort.getPrefs().getOrExcept("iserial"));
- } catch (Exception e) {
- // if serial port does not contain an iserial field
+ // retrigger a discovery
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().setUploadInProgress(true);
+ Thread.sleep(100);
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().forceRefresh();
+ Thread.sleep(100);
}
prefs.put("build.path", buildPath);
@@ -170,15 +188,22 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
boolean uploadResult;
try {
+ // Architecture field formatted as "arduino.avr" to prepend runtime vars
String pattern = prefs.getOrExcept("upload.pattern");
- String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ String arch = targetPlatform.getContainerPackage().getId()+"."+targetPlatform.getId();
+ String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
uploadResult = executeUploadCommand(cmd);
} catch (RunnerException e) {
throw e;
} catch (Exception e) {
throw new RunnerException(e);
+ } finally {
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false);
}
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().setUploadInProgress(false);
+ BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false);
+
String finalUploadPort = null;
if (uploadResult && doTouch) {
try {
@@ -191,15 +216,13 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
long started = System.currentTimeMillis();
while (System.currentTimeMillis() - started < 2000) {
List portList = Serial.list();
- if (portList.contains(actualUploadPort)) {
- finalUploadPort = actualUploadPort;
- break;
- } else if (portList.contains(userSelectedUploadPort)) {
+ if (portList.contains(userSelectedUploadPort)) {
finalUploadPort = userSelectedUploadPort;
break;
}
Thread.sleep(250);
}
+ finalUploadPort = actualUploadPort;
}
} catch (InterruptedException ex) {
// noop
@@ -213,6 +236,7 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String
finalUploadPort = userSelectedUploadPort;
}
BaseNoGui.selectSerialPort(finalUploadPort);
+
return uploadResult;
}
@@ -247,11 +271,10 @@ private String waitForUploadPort(String uploadPort, List before) throws
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)) {
+ // On Windows and OS X, it can take a few seconds for the port to disappear and
+ // come back, so use a time out before assuming that the selected port is the
+ // bootloader (not the sketch).
+ if (elapsed >= 5000 && now.contains(uploadPort)) {
if (verbose)
System.out.println("Uploading using selected port: " + uploadPort);
return uploadPort;
@@ -300,7 +323,8 @@ private boolean uploadUsingProgrammer(String buildPath, String className) throws
// }
String pattern = prefs.getOrExcept("program.pattern");
- String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ String arch = targetPlatform.getContainerPackage().getId()+"."+targetPlatform.getId();
+ String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
return executeUploadCommand(cmd);
} catch (RunnerException e) {
throw e;
@@ -363,12 +387,13 @@ public boolean burnBootloader() throws Exception {
new LoadVIDPIDSpecificPreferences().load(prefs);
String pattern = prefs.getOrExcept("erase.pattern");
- String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ String arch = targetPlatform.getContainerPackage().getId()+"."+targetPlatform.getId();
+ String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
if (!executeUploadCommand(cmd))
return false;
pattern = prefs.getOrExcept("bootloader.pattern");
- cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
+ cmd = StringReplacer.formatAndSplit(pattern, prefs, arch, true);
return executeUploadCommand(cmd);
}
}
diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java
index a2eab2559d6..eb5e107ba21 100644
--- a/arduino-core/src/processing/app/BaseNoGui.java
+++ b/arduino-core/src/processing/app/BaseNoGui.java
@@ -33,6 +33,8 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import cc.arduino.packages.BoardPort;
+
import static processing.app.I18n.tr;
import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS;
@@ -857,6 +859,10 @@ public static void createToolPreferences(Collection installedTo
}
PreferencesData.set(prefix + tool.getName() + ".path", absolutePath);
PreferencesData.set(prefix + tool.getName() + "-" + tool.getVersion() + ".path", absolutePath);
+ for (String userArch : tool.ugetUserArchitectures()) {
+ PreferencesData.set(prefix + tool.getName() + ".path." + userArch, absolutePath);
+ PreferencesData.set(prefix + tool.getName() + "-" + tool.getVersion() + ".path." + userArch, absolutePath);
+ }
}
}
@@ -1119,6 +1125,10 @@ static public void selectBoard(TargetBoard targetBoard) {
public static void selectSerialPort(String port) {
PreferencesData.set("serial.port", port);
+ BoardPort boardPort = getDiscoveryManager().find(port, true);
+ if (boardPort != null) {
+ PreferencesData.set("serial.port.iserial", boardPort.getPrefs().get("iserial"));
+ }
String portFile = port;
if (port.startsWith("/dev/")) {
portFile = portFile.substring(5);
diff --git a/arduino-core/src/processing/app/Platform.java b/arduino-core/src/processing/app/Platform.java
index 29e5e733d87..0c2c1d8cbbd 100644
--- a/arduino-core/src/processing/app/Platform.java
+++ b/arduino-core/src/processing/app/Platform.java
@@ -35,6 +35,8 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.ArrayList;
+import java.util.Arrays;
import static processing.app.I18n.tr;
@@ -160,13 +162,26 @@ private static void loadLib(File lib) {
}
}
- public native String resolveDeviceAttachedToNative(String serial);
+ private native String resolveDeviceAttachedToNative(String serial);
+ private native String[] listSerialsNative();
public String preListAllCandidateDevices() {
return null;
}
- public Map resolveDeviceByVendorIdProductId(String serial, Map packages, String devicesListOutput) {
+ public List listSerials(){
+ return new ArrayList(Arrays.asList(this.listSerialsNative()));
+ }
+
+ public List listSerialsNames(){
+ List list = new LinkedList<>();
+ for (String port : this.listSerialsNative()) {
+ list.add(port.split("_")[0]);
+ }
+ return list;
+ }
+
+ public synchronized Map resolveDeviceByVendorIdProductId(String serial, Map packages) {
String vid_pid_iSerial = resolveDeviceAttachedToNative(serial);
for (TargetPackage targetPackage : packages.values()) {
for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) {
diff --git a/arduino-core/src/processing/app/helpers/StringReplacer.java b/arduino-core/src/processing/app/helpers/StringReplacer.java
index f51bfd7b696..18bb9154efb 100644
--- a/arduino-core/src/processing/app/helpers/StringReplacer.java
+++ b/arduino-core/src/processing/app/helpers/StringReplacer.java
@@ -29,12 +29,17 @@ public class StringReplacer {
public static String[] formatAndSplit(String src, Map dict,
boolean recursive) throws Exception {
+ return formatAndSplit(src, dict, "", recursive);
+ }
+
+ public static String[] formatAndSplit(String src, Map dict, String arch,
+ boolean recursive) throws Exception {
String res;
// Recursive replace with a max depth of 10 levels.
for (int i = 0; i < 10; i++) {
// Do a replace with dictionary
- res = StringReplacer.replaceFromMapping(src, dict);
+ res = StringReplacer.replaceFromMapping(src, dict, arch);
if (!recursive)
break;
if (res.equals(src))
@@ -85,16 +90,32 @@ public static String[] quotedSplit(String src, String quoteChars,
return res.toArray(new String[0]);
}
+ public static String replaceFromMapping(String src, Map map, String arch) {
+ return replaceFromMapping(src, map, "{", "}", arch);
+ }
+
public static String replaceFromMapping(String src, Map map) {
- return replaceFromMapping(src, map, "{", "}");
+ return replaceFromMapping(src, map, "{", "}", "");
}
public static String replaceFromMapping(String src, Map map,
String leftDelimiter,
- String rightDelimiter) {
+ String rightDelimiter,
+ String footer) {
for (Map.Entry entry : map.entrySet()) {
String keyword = leftDelimiter + entry.getKey() + rightDelimiter;
- src = src.replace(keyword, entry.getValue());
+ String value = null;
+
+ // if {entry.getKey()+"."+footer} key exists, use it instead
+ if (map.containsKey(entry.getKey()+"."+footer)) {
+ value = map.get(entry.getKey()+"."+footer);
+ } else {
+ value = entry.getValue();
+ }
+
+ if (value != null && keyword != null) {
+ src = src.replace(keyword, entry.getValue());
+ }
}
return src;
}
diff --git a/arduino-core/src/processing/app/packages/LibraryList.java b/arduino-core/src/processing/app/packages/LibraryList.java
index d4d504cea79..5c9c096dbf5 100644
--- a/arduino-core/src/processing/app/packages/LibraryList.java
+++ b/arduino-core/src/processing/app/packages/LibraryList.java
@@ -50,29 +50,29 @@ public LibraryList(List ideLibs) {
super(ideLibs);
}
- public UserLibrary getByName(String name) {
+ public synchronized UserLibrary getByName(String name) {
for (UserLibrary l : this)
if (l.getName().equals(name))
return l;
return null;
}
- public void addOrReplace(UserLibrary lib) {
+ public synchronized void addOrReplace(UserLibrary lib) {
remove(lib);
add(lib);
}
- public void remove(UserLibrary lib) {
+ public synchronized void remove(UserLibrary lib) {
UserLibrary l = getByName(lib.getName());
if (l != null)
super.remove(l);
}
- public void sort() {
+ public synchronized void sort() {
Collections.sort(this, UserLibrary.CASE_INSENSITIVE_ORDER);
}
- public LibraryList filterLibrariesInSubfolder(File subFolder) {
+ public synchronized LibraryList filterLibrariesInSubfolder(File subFolder) {
LibraryList res = new LibraryList();
for (UserLibrary lib : this) {
if (FileUtils.isSubDirectory(subFolder, lib.getInstalledFolder())) {
@@ -82,7 +82,7 @@ public LibraryList filterLibrariesInSubfolder(File subFolder) {
return res;
}
- public boolean hasLibrary(UserLibrary lib) {
+ public synchronized boolean hasLibrary(UserLibrary lib) {
for (UserLibrary l : this)
if (l == lib) return true;
return false;
diff --git a/arduino-core/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java b/arduino-core/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java
deleted file mode 100644
index fe9c2571578..00000000000
--- a/arduino-core/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package processing.app.zeroconf.jmdns;
-
-import javax.jmdns.impl.DNSIncoming;
-import javax.jmdns.impl.DNSTaskStarter;
-import javax.jmdns.impl.JmDNSImpl;
-import javax.jmdns.impl.ServiceInfoImpl;
-import javax.jmdns.impl.tasks.RecordReaper;
-import java.util.Timer;
-
-public class ArduinoDNSTaskStarter implements DNSTaskStarter.Factory.ClassDelegate {
-
- @Override
- public DNSTaskStarter newDNSTaskStarter(final JmDNSImpl jmDNSImpl) {
- final DNSTaskStarter.DNSTaskStarterImpl delegate = new DNSTaskStarter.DNSTaskStarterImpl(jmDNSImpl);
- final DNSTaskStarter.DNSTaskStarterImpl.StarterTimer timer = new DNSTaskStarter.DNSTaskStarterImpl.StarterTimer("JmDNS(" + jmDNSImpl.getName() + ").Timer", true);
-
- return new DNSTaskStarter() {
-
- public void purgeTimer() {
- delegate.purgeTimer();
- timer.purge();
- }
-
- public void purgeStateTimer() {
- delegate.purgeStateTimer();
- }
-
- public void cancelTimer() {
- delegate.cancelTimer();
- timer.cancel();
- }
-
- public void cancelStateTimer() {
- delegate.cancelStateTimer();
- }
-
- public void startProber() {
- delegate.startProber();
- }
-
- public void startAnnouncer() {
- delegate.startAnnouncer();
- }
-
- public void startRenewer() {
- delegate.startRenewer();
- }
-
- public void startCanceler() {
- delegate.startCanceler();
- }
-
- public void startReaper() {
- new RecordReaper(jmDNSImpl) {
- @Override
- public void start(Timer timer) {
- if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) {
- timer.schedule(this, 0, 500);
- }
- }
- }.start(timer);
- }
-
- public void startServiceInfoResolver(ServiceInfoImpl info) {
- delegate.startServiceInfoResolver(info);
- }
-
- public void startTypeResolver() {
- delegate.startTypeResolver();
- }
-
- public void startServiceResolver(String type) {
- delegate.startServiceResolver(type);
- }
-
- public void startResponder(DNSIncoming in, int port) {
- delegate.startResponder(in, port);
- }
- };
- }
-}
diff --git a/build/build.xml b/build/build.xml
index 43464da190c..6f83f086603 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -436,12 +436,12 @@
-
-
-
+
+
+
-
+
@@ -639,12 +639,12 @@
-
-
-
+
+
+
-
+
@@ -796,12 +796,9 @@
-
-
+
-
-
-
+
@@ -908,12 +905,12 @@
-
-
-
+
+
+
-
+
diff --git a/build/liblistSerials-1.0.5.zip.sha b/build/liblistSerials-1.0.5.zip.sha
deleted file mode 100644
index 6484b2fbc08..00000000000
--- a/build/liblistSerials-1.0.5.zip.sha
+++ /dev/null
@@ -1 +0,0 @@
-edb1c858a243e465f5797d7e5d0baa66daa1eba0
diff --git a/build/liblistSerials-1.0.7.zip.sha b/build/liblistSerials-1.0.7.zip.sha
new file mode 100644
index 00000000000..8a43a7fe9c7
--- /dev/null
+++ b/build/liblistSerials-1.0.7.zip.sha
@@ -0,0 +1 @@
+6ddda4d86d49a4b496718b401b8cc91117bd2930
diff --git a/build/windows/launcher/config.xml b/build/windows/launcher/config.xml
index 0bfadc6632a..496f6d56df2 100644
--- a/build/windows/launcher/config.xml
+++ b/build/windows/launcher/config.xml
@@ -41,7 +41,7 @@
%EXEDIR%/lib/jackson-databind-2.6.3.jar
%EXEDIR%/lib/jackson-module-mrbean-2.6.3.jar
%EXEDIR%/lib/java-semver-0.8.0.jar
- %EXEDIR%/lib/jmdns-3.4.1.jar
+ %EXEDIR%/lib/jmdns-3.4.2.jar
%EXEDIR%/lib/jna-4.1.0.jar
%EXEDIR%/lib/jna-platform-4.1.0.jar
%EXEDIR%/lib/jsch-0.1.50.jar
diff --git a/build/windows/launcher/config_debug.xml b/build/windows/launcher/config_debug.xml
index 708ef610fdf..8c9da11eb2d 100644
--- a/build/windows/launcher/config_debug.xml
+++ b/build/windows/launcher/config_debug.xml
@@ -41,7 +41,7 @@
%EXEDIR%/lib/jackson-databind-2.6.3.jar
%EXEDIR%/lib/jackson-module-mrbean-2.6.3.jar
%EXEDIR%/lib/java-semver-0.8.0.jar
- %EXEDIR%/lib/jmdns-3.4.1.jar
+ %EXEDIR%/lib/jmdns-3.4.2.jar
%EXEDIR%/lib/jna-4.1.0.jar
%EXEDIR%/lib/jna-platform-4.1.0.jar
%EXEDIR%/lib/jsch-0.1.50.jar
diff --git a/hardware/arduino/avr/cores/arduino/CDC.cpp b/hardware/arduino/avr/cores/arduino/CDC.cpp
index f19b44c7f1e..f6750665105 100644
--- a/hardware/arduino/avr/cores/arduino/CDC.cpp
+++ b/hardware/arduino/avr/cores/arduino/CDC.cpp
@@ -34,6 +34,8 @@ typedef struct
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
static volatile int32_t breakValue = -1;
+bool _updatedLUFAbootloader = false;
+
#define WEAK __attribute__ ((weak))
extern const CDCDescriptor _cdcInterface PROGMEM;
@@ -99,24 +101,32 @@ bool CDC_Setup(USBSetup& setup)
// with a relatively long period so it can finish housekeeping tasks
// like servicing endpoints before the sketch ends
-#ifndef MAGIC_KEY
-#define MAGIC_KEY 0x7777
-#endif
-#ifndef MAGIC_KEY_POS
-#define MAGIC_KEY_POS 0x0800
+ uint16_t magic_key_pos = MAGIC_KEY_POS;
+
+// If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
+// This is used to keep compatible with the old leonardo bootloaders.
+// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
+#if MAGIC_KEY_POS != (RAMEND-1)
+ // For future boards save the key in the inproblematic RAMEND
+ // Which is reserved for the main() return value (which will never return)
+ if (_updatedLUFAbootloader) {
+ // horray, we got a new bootloader!
+ magic_key_pos = (RAMEND-1);
+ }
#endif
// We check DTR state to determine if host port is open (bit 0 of lineState).
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
{
#if MAGIC_KEY_POS != (RAMEND-1)
- *(uint16_t *)(RAMEND-1) = *(uint16_t *)MAGIC_KEY_POS;
- *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY;
-#else
- // for future boards save the key in the inproblematic RAMEND
- // which is reserved for the main() return value (which will never return)
- *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY;
+ // Backup ram value if its not a newer bootloader.
+ // This should avoid memory corruption at least a bit, not fully
+ if (magic_key_pos != (RAMEND-1)) {
+ *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
+ }
#endif
+ // Store boot key
+ *(uint16_t *)magic_key_pos = MAGIC_KEY;
wdt_enable(WDTO_120MS);
}
else
@@ -129,10 +139,14 @@ bool CDC_Setup(USBSetup& setup)
wdt_disable();
wdt_reset();
#if MAGIC_KEY_POS != (RAMEND-1)
- *(uint16_t *)MAGIC_KEY_POS = *(uint16_t *)(RAMEND-1);
-#else
- *(uint16_t *)MAGIC_KEY_POS = 0x0000;
+ // Restore backed up (old bootloader) magic key data
+ if (magic_key_pos != (RAMEND-1)) {
+ *(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
+ } else {
#endif
+ // Clean up RAMEND key
+ *(uint16_t *)magic_key_pos = 0x0000;
+ }
}
}
return true;
diff --git a/hardware/arduino/avr/cores/arduino/USBCore.cpp b/hardware/arduino/avr/cores/arduino/USBCore.cpp
index 62b90ed47d6..248da62732e 100644
--- a/hardware/arduino/avr/cores/arduino/USBCore.cpp
+++ b/hardware/arduino/avr/cores/arduino/USBCore.cpp
@@ -35,6 +35,7 @@ extern const u8 STRING_PRODUCT[] PROGMEM;
extern const u8 STRING_MANUFACTURER[] PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptorB PROGMEM;
+extern bool _updatedLUFAbootloader;
const u16 STRING_LANGUAGE[2] = {
(3<<8) | (2+2),
@@ -115,16 +116,10 @@ static inline void Recv(volatile u8* data, u8 count)
{
while (count--)
*data++ = UEDATX;
-
- RXLED1; // light the RX LED
- RxLEDPulse = TX_RX_LED_PULSE_MS;
}
static inline u8 Recv8()
{
- RXLED1; // light the RX LED
- RxLEDPulse = TX_RX_LED_PULSE_MS;
-
return UEDATX;
}
@@ -226,6 +221,9 @@ int USB_Recv(u8 ep, void* d, int len)
if (!_usbConfiguration || len < 0)
return -1;
+ RXLED1; // light the RX LED
+ RxLEDPulse = TX_RX_LED_PULSE_MS;
+
LockEP lock(ep);
u8 n = FifoByteCount();
len = min(n,len);
@@ -806,6 +804,12 @@ void USBDevice_::attach()
UDIEN = (1<