From 6d5597b070c7bedce15047c7c560249965cc0bfc Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 25 Jan 2016 18:19:48 +0100 Subject: [PATCH 01/12] Avoid multiple concurrent compile/upload operations Disable Compile/Run buttons as they get press, and reenable only on function exit. The launched upload process has now a 2minutes timeout before being terminated forcefully. 10 second after pressing "Upload" the button comes pressable again, but this time the previous upload command gets killed explicitely --- app/src/processing/app/Editor.java | 29 +++++++++++++++++-- app/src/processing/app/EditorToolbar.java | 11 +++++-- .../src/cc/arduino/packages/Uploader.java | 13 +++++++-- .../packages/uploaders/SerialUploader.java | 8 ++++- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 8da903bcb2f..12560e5bf7f 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -146,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. @@ -198,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"); @@ -1648,6 +1650,7 @@ private void resetHandlers() { stopHandler = new DefaultStopHandler(); exportHandler = new DefaultExportHandler(); exportAppHandler = new DefaultExportAppHandler(); + timeoutUploadHandler = new TimeoutUploadHandler(); } @@ -1979,6 +1982,7 @@ public void run() { status.unprogress(); toolbar.deactivateRun(); + avoidMultipleOperations = false; } } @@ -2367,6 +2371,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(); } @@ -2406,6 +2411,7 @@ public void run() { e.printStackTrace(); } finally { populatePortMenu(); + avoidMultipleOperations = false; } status.unprogress(); uploading = false; @@ -2500,6 +2506,7 @@ public void run() { } catch (Exception e) { e.printStackTrace(); } finally { + avoidMultipleOperations = false; populatePortMenu(); } status.unprogress(); @@ -2514,6 +2521,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) { @@ -2558,7 +2579,7 @@ public void handleSerial() { // 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) { @@ -2582,8 +2603,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?")); 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/arduino-core/src/cc/arduino/packages/Uploader.java b/arduino-core/src/cc/arduino/packages/Uploader.java index d58d29504f5..1d1967c3657 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; @@ -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,11 +125,16 @@ 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(); + } + result = process.exitValue(); } catch (Exception e) { e.printStackTrace(); } diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java index 971bfb8c6f9..64b66862dd4 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java @@ -78,6 +78,11 @@ 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) { @@ -134,7 +139,7 @@ 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); } } catch (SerialException e) { @@ -213,6 +218,7 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String finalUploadPort = userSelectedUploadPort; } BaseNoGui.selectSerialPort(finalUploadPort); + return uploadResult; } From c11ceb7daeb3de2ea5403cb990094270c335e4a3 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 25 Jan 2016 18:29:25 +0100 Subject: [PATCH 02/12] Fix NPE when replacing unexisting strings --- arduino-core/src/processing/app/helpers/StringReplacer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arduino-core/src/processing/app/helpers/StringReplacer.java b/arduino-core/src/processing/app/helpers/StringReplacer.java index f51bfd7b696..fae77155aef 100644 --- a/arduino-core/src/processing/app/helpers/StringReplacer.java +++ b/arduino-core/src/processing/app/helpers/StringReplacer.java @@ -94,7 +94,9 @@ public static String replaceFromMapping(String src, Map map, String rightDelimiter) { for (Map.Entry entry : map.entrySet()) { String keyword = leftDelimiter + entry.getKey() + rightDelimiter; - src = src.replace(keyword, entry.getValue()); + if (entry.getValue() != null && keyword != null) { + src = src.replace(keyword, entry.getValue()); + } } return src; } From 243fc68763058be1f6037fc4072a3f3b2a9dbaf1 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 25 Jan 2016 18:31:27 +0100 Subject: [PATCH 03/12] Rework Serial ports handling and add Board info menu This commit introduces the concept of stateful board list (vs. original stateless) and board serial number. The board is now an "entity" composed by the triplet port/vid/pid. These informations come from libListSerial "light" function. When the board list changes, it triggers a request for the additional infos to libListSerial. These information contains the serial number of the boards. These brings a lighter and faster scanning process. Some logic has been introduced to handle a board with the S/N only exposed in the bootloader (like 32u4). In this case the disappearing port acquires the bootloader's S/N A menu (under Ports menu) shows the currently connected port info and can be used for bugreporting --- app/src/processing/app/Editor.java | 49 ++++++++++ app/src/processing/app/EditorLineStatus.java | 5 + .../src/cc/arduino/packages/BoardPort.java | 36 ++++++++ .../src/cc/arduino/packages/Discovery.java | 1 + .../cc/arduino/packages/DiscoveryManager.java | 27 +++++- .../discoverers/NetworkDiscovery.java | 7 ++ .../packages/discoverers/SerialDiscovery.java | 34 +++++-- .../serial/SerialBoardsLister.java | 92 +++++++++++++++---- .../packages/uploaders/SerialUploader.java | 21 +++-- .../src/processing/app/BaseNoGui.java | 4 + arduino-core/src/processing/app/Platform.java | 19 +++- 11 files changed, 257 insertions(+), 38 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 12560e5bf7f..07af0a1c162 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -814,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(); @@ -2753,6 +2756,52 @@ 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 = ""; + boolean found = false; + + for (BoardPort port : ports) { + if (port.getAddress().equals(selectedPort)) { + label = port.getBoardName(); + vid = port.getVID(); + pid = port.getPID(); + iserial = port.getISerial(); + found = true; + break; + } + } + + if (!found) { + statusNotice(tr("Please select a port to obtain board 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/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/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java index ebbb8c50df1..e88568a1e42 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java @@ -67,6 +67,13 @@ public List listDiscoveredBoards() { } } + @Override + public List listDiscoveredBoards(boolean complete) { + synchronized (reachableBoardPorts) { + return new LinkedList<>(reachableBoardPorts); + } + } + public void setReachableBoardPorts(List newReachableBoardPorts) { synchronized (reachableBoardPorts) { this.reachableBoardPorts.clear(); diff --git a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java index 9c3efdc5200..565e80e90bf 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,43 @@ 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(); + } + + public void setUploadInProgress(boolean param) { + serialBoardsLister.uploadInProgress = 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/serial/SerialBoardsLister.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java index 5ca99819b89..b4ac2da9dc4 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -31,9 +31,9 @@ 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.*; @@ -41,6 +41,10 @@ public class SerialBoardsLister extends TimerTask { private final SerialDiscovery serialDiscovery; + private final List boardPorts = new LinkedList<>(); + private List oldPorts = new LinkedList<>(); + public boolean uploadInProgress = false; + private BoardPort oldUploadBoardPort = null; public SerialBoardsLister(SerialDiscovery serialDiscovery) { this.serialDiscovery = serialDiscovery; @@ -50,8 +54,7 @@ public void start(Timer timer) { timer.schedule(this, 0, 1000); } - @Override - public void run() { + public void retriggerDiscovery() { while (BaseNoGui.packages == null) { try { Thread.sleep(1000); @@ -59,34 +62,79 @@ public void run() { // noop } } - Platform platform = BaseNoGui.getPlatform(); if (platform == null) { return; } - List boardPorts = new LinkedList<>(); + 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(); + 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 +144,25 @@ 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() { + retriggerDiscovery(); + } } diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java index 64b66862dd4..064e04cfa89 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; @@ -156,13 +158,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); @@ -184,6 +185,8 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String throw new RunnerException(e); } + BaseNoGui.getDiscoveryManager().getSerialDiscoverer().setUploadInProgress(false); + String finalUploadPort = null; if (uploadResult && doTouch) { try { @@ -196,15 +199,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 diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index a2eab2559d6..f1d9d9f7d95 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; @@ -1119,6 +1121,8 @@ static public void selectBoard(TargetBoard targetBoard) { public static void selectSerialPort(String port) { PreferencesData.set("serial.port", port); + BoardPort boardPort = getDiscoveryManager().find(port, true); + 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..b999c8264dc 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 Map resolveDeviceByVendorIdProductId(String serial, Map packages) { String vid_pid_iSerial = resolveDeviceAttachedToNative(serial); for (TargetPackage targetPackage : packages.values()) { for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) { From e23bbf76c112fe13fc9aabd36eaf5b1a0793cd53 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 5 Feb 2016 12:53:32 +0100 Subject: [PATCH 04/12] avoid NPE in CLI mode (boardInfo not yet initialized) --- arduino-core/src/processing/app/BaseNoGui.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index f1d9d9f7d95..a431a19d7ec 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -1122,7 +1122,9 @@ static public void selectBoard(TargetBoard targetBoard) { public static void selectSerialPort(String port) { PreferencesData.set("serial.port", port); BoardPort boardPort = getDiscoveryManager().find(port, true); - PreferencesData.set("serial.port.iserial", boardPort.getPrefs().get("iserial")); + if (boardPort != null) { + PreferencesData.set("serial.port.iserial", boardPort.getPrefs().get("iserial")); + } String portFile = port; if (port.startsWith("/dev/")) { portFile = portFile.substring(5); From 821c665460373d681973733eaece93fa2185e871 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 3 Mar 2016 10:48:50 +0100 Subject: [PATCH 05/12] Change message if requiring infos from Network port --- app/src/processing/app/Editor.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 07af0a1c162..aef2bcdb895 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2766,6 +2766,7 @@ private void handleBoardInfo() { String vid = ""; String pid = ""; String iserial = ""; + String protocol = ""; boolean found = false; for (BoardPort port : ports) { @@ -2774,6 +2775,7 @@ private void handleBoardInfo() { vid = port.getVID(); pid = port.getPID(); iserial = port.getISerial(); + protocol = port.getProtocol(); found = true; break; } @@ -2784,6 +2786,11 @@ private void handleBoardInfo() { 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; From 52ef55380d824da016d0562d396ceabe88b7edd1 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 23 Feb 2016 15:59:21 +0100 Subject: [PATCH 06/12] avoid NPE if serial monitor is waiting too long for opening --- app/src/processing/app/Editor.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index aef2bcdb895..d018b69b278 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2442,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); From ad74288e5aea89ec88fa25005bf2e9c779ff5b27 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 8 Mar 2016 10:20:51 +0100 Subject: [PATCH 07/12] Fix randomic NPE when pressing menus during operations --- arduino-core/src/cc/arduino/packages/Uploader.java | 6 +++++- arduino-core/src/processing/app/Platform.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/Uploader.java b/arduino-core/src/cc/arduino/packages/Uploader.java index 1d1967c3657..cd9a11a4521 100644 --- a/arduino-core/src/cc/arduino/packages/Uploader.java +++ b/arduino-core/src/cc/arduino/packages/Uploader.java @@ -134,7 +134,11 @@ protected boolean executeUploadCommand(String command[]) throws Exception { if (!process.waitFor(2, TimeUnit.MINUTES)) { process.destroyForcibly(); } - result = process.exitValue(); + if (!process.isAlive()) { + result = process.exitValue(); + } else { + result = 0; + } } catch (Exception e) { e.printStackTrace(); } diff --git a/arduino-core/src/processing/app/Platform.java b/arduino-core/src/processing/app/Platform.java index b999c8264dc..0c2c1d8cbbd 100644 --- a/arduino-core/src/processing/app/Platform.java +++ b/arduino-core/src/processing/app/Platform.java @@ -181,7 +181,7 @@ public List listSerialsNames(){ return list; } - public Map resolveDeviceByVendorIdProductId(String serial, Map packages) { + 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()) { From ea405ea534771b695054aa1227c20109ee89cf47 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 25 Mar 2016 13:39:13 +0100 Subject: [PATCH 08/12] avoid NPE for synchronization issues on board list --- .../arduino/packages/discoverers/serial/SerialBoardsLister.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b4ac2da9dc4..4de3626f612 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -54,7 +54,7 @@ public void start(Timer timer) { timer.schedule(this, 0, 1000); } - public void retriggerDiscovery() { + public synchronized void retriggerDiscovery() { while (BaseNoGui.packages == null) { try { Thread.sleep(1000); From c5d88f09aecf35ee16ec09fa3c78495ab1817dcb Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 25 Mar 2016 17:02:19 +0100 Subject: [PATCH 09/12] add a flag to pause polling for serial port --- .../cc/arduino/packages/discoverers/SerialDiscovery.java | 4 +++- .../packages/discoverers/serial/SerialBoardsLister.java | 9 +++++++-- .../cc/arduino/packages/uploaders/SerialUploader.java | 9 +++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java index 565e80e90bf..3e6646d6732 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java @@ -75,13 +75,15 @@ public void setSerialBoardPorts(List newSerialBoardPorts) { } public void forceRefresh() { - serialBoardsLister.retriggerDiscovery(); + 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()); 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 4de3626f612..0cafed95690 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -44,6 +44,7 @@ public class SerialBoardsLister extends TimerTask { 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) { @@ -54,7 +55,7 @@ public void start(Timer timer) { timer.schedule(this, 0, 1000); } - public synchronized void retriggerDiscovery() { + public synchronized void retriggerDiscovery(boolean polled) { while (BaseNoGui.packages == null) { try { Thread.sleep(1000); @@ -67,6 +68,10 @@ public synchronized void retriggerDiscovery() { return; } + if (polled && pausePolling) { + return; + } + List ports = platform.listSerials(); if (ports.equals(oldPorts)) { return; @@ -163,6 +168,6 @@ public synchronized void retriggerDiscovery() { @Override public void run() { - retriggerDiscovery(); + retriggerDiscovery(true); } } diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java index 064e04cfa89..19d8a802de6 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java @@ -91,6 +91,8 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String return uploadUsingProgrammer(buildPath, className); } + BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(true); + if (noUploadPort) { prefs.put("build.path", buildPath); @@ -107,6 +109,8 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String uploadResult = executeUploadCommand(cmd); } catch (Exception e) { throw new RunnerException(e); + } finally { + BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false); } return uploadResult; } @@ -148,6 +152,8 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String throw new RunnerException(e); } catch (InterruptedException e) { throw new RunnerException(e.getMessage()); + } finally { + BaseNoGui.getDiscoveryManager().getSerialDiscoverer().pausePolling(false); } if (actualUploadPort == null) { actualUploadPort = userSelectedUploadPort; @@ -183,9 +189,12 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String 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) { From a6a623658d97036b1a45ea038c2ebefcc5bebef3 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 1 Apr 2016 11:40:32 +0200 Subject: [PATCH 10/12] update libListSerials to 1.1.0 --- build/build.xml | 25 +++++++++++++------------ build/liblistSerials-1.0.5.zip.sha | 1 - build/liblistSerials-1.1.0.zip.sha | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) delete mode 100644 build/liblistSerials-1.0.5.zip.sha create mode 100644 build/liblistSerials-1.1.0.zip.sha diff --git a/build/build.xml b/build/build.xml index 43464da190c..444c6502bff 100644 --- a/build/build.xml +++ b/build/build.xml @@ -78,6 +78,7 @@ + @@ -436,12 +437,12 @@ - - - + + + - + @@ -639,12 +640,12 @@ - - - + + + - + @@ -908,12 +909,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.1.0.zip.sha b/build/liblistSerials-1.1.0.zip.sha new file mode 100644 index 00000000000..f4bc4a9a239 --- /dev/null +++ b/build/liblistSerials-1.1.0.zip.sha @@ -0,0 +1 @@ +05e942bc85e46a2b59e01fe1333dd9472e465654 From 72c337d88df24b980268df844dfa920d73939d69 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 5 Apr 2016 19:08:16 +0200 Subject: [PATCH 11/12] avoid losing the sketch serial port on 1200bps touch --- .../src/cc/arduino/packages/uploaders/SerialUploader.java | 1 - 1 file changed, 1 deletion(-) diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java index 19d8a802de6..a850e23f762 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java @@ -214,7 +214,6 @@ public boolean uploadUsingPreferences(File sourcePath, String buildPath, String } Thread.sleep(250); } - finalUploadPort = actualUploadPort; } } catch (InterruptedException ex) { // noop From bf11c7f3950c2bea4a4cd2ec9b8e8a870c5730f2 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 6 Apr 2016 17:52:24 +0200 Subject: [PATCH 12/12] avoid queuing a lot of threads while waiting for platform --- .../discoverers/serial/SerialBoardsLister.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 0cafed95690..77d2922e7a2 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -56,13 +56,6 @@ public void start(Timer timer) { } public synchronized void retriggerDiscovery(boolean polled) { - while (BaseNoGui.packages == null) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // noop - } - } Platform platform = BaseNoGui.getPlatform(); if (platform == null) { return; @@ -103,6 +96,11 @@ public synchronized void retriggerDiscovery(boolean polled) { String[] parts = newPort.split("_"); String port = parts[0]; + if (parts.length != 3) { + // something went horribly wrong + continue; + } + Map boardData = platform.resolveDeviceByVendorIdProductId(port, BaseNoGui.packages); BoardPort boardPort = null; @@ -168,6 +166,9 @@ public synchronized void retriggerDiscovery(boolean polled) { @Override public void run() { + if (BaseNoGui.packages == null) { + return; + } retriggerDiscovery(true); } }