From f81798badfd31069566db5a4adb0c45a1327397f Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 10 Sep 2018 14:04:10 +0200 Subject: [PATCH 01/28] Pluggable discovery: search in platform.txt (WIP) --- .../cc/arduino/packages/DiscoveryManager.java | 46 ++++++++- .../discoverers/PluggableDiscovery.java | 99 +++++++++++++++++++ .../src/processing/app/BaseNoGui.java | 4 +- 3 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java diff --git a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java index b1ec50d85..f8b239401 100644 --- a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java +++ b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java @@ -29,13 +29,20 @@ package cc.arduino.packages; -import cc.arduino.packages.discoverers.NetworkDiscovery; -import cc.arduino.packages.discoverers.SerialDiscovery; +import static processing.app.I18n.format; +import static processing.app.I18n.tr; import java.util.ArrayList; import java.util.List; +import java.util.Map; -import static processing.app.I18n.tr; +import cc.arduino.packages.discoverers.PluggableDiscovery; +import cc.arduino.packages.discoverers.NetworkDiscovery; +import cc.arduino.packages.discoverers.SerialDiscovery; +import processing.app.debug.TargetPackage; +import processing.app.debug.TargetPlatform; +import processing.app.helpers.PreferencesMap; +import processing.app.helpers.StringReplacer; public class DiscoveryManager { @@ -43,17 +50,46 @@ public class DiscoveryManager { private final SerialDiscovery serialDiscoverer = new SerialDiscovery(); private final NetworkDiscovery networkDiscoverer = new NetworkDiscovery(); - public DiscoveryManager() { +// private final Map packages; + + public DiscoveryManager(Map packages) { +// this.packages = packages; + discoverers = new ArrayList<>(); discoverers.add(serialDiscoverer); discoverers.add(networkDiscoverer); + // Search for discoveries in installed packages + for (TargetPackage targetPackage : packages.values()) { + for (TargetPlatform platform: targetPackage.getPlatforms().values()) { + //System.out.println("installed: "+platform); + PreferencesMap prefs = platform.getPreferences().subTree("discovery"); + for (String discoveryName : prefs.firstLevelMap().keySet()) { + PreferencesMap discoveryPrefs = prefs.subTree(discoveryName); + + String pattern = discoveryPrefs.get("pattern"); + if (pattern == null) { + System.out.println(format(tr("No recipes defined for discovery '{0}'"),discoveryName)); + continue; + } + try { + System.out.println("found discovery: " + discoveryName + " -> " + pattern); + System.out.println("with preferencess -> " + discoveryPrefs); + String[] cmd = StringReplacer.formatAndSplit(pattern, discoveryPrefs); + discoverers.add(new PluggableDiscovery(discoveryName, cmd)); + } catch (Exception e) { + System.out.println(format(tr("Could not start discovery '{0}': {1}"), discoveryName, e.getMessage())); + } + } + } + } + // Start all discoverers for (Discovery d : discoverers) { try { new Thread(d).start(); } catch (Exception e) { - System.err.println(tr("Error starting discovery method: ") + d.getClass()); + System.err.println(tr("Error starting discovery method: ") + d.toString()); e.printStackTrace(); } } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java new file mode 100644 index 000000000..8bd435087 --- /dev/null +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -0,0 +1,99 @@ +/* + * 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 2018 Arduino SA (http://www.arduino.cc/) + */ + +package cc.arduino.packages.discoverers; + +import java.util.ArrayList; +import java.util.List; + +import cc.arduino.packages.BoardPort; +import cc.arduino.packages.Discovery; +import processing.app.legacy.PApplet; + +public class PluggableDiscovery implements Discovery { + + private String discoveryName; + + public PluggableDiscovery(String discoveryName, String[] cmd) { + this.discoveryName = discoveryName; + System.out.println("Starting: " + PApplet.join(cmd, " ")); + } + + @Override + public void run() { + // TODO this method is started as a new thread, it will constantly + // communicate with the discovery tool and keep track of the discovered + // port to be returned from listDiscoveredBoard() + try { + start(); + while (true) { // TODO: Find a better way to terminate discovery + System.out.println(discoveryName + ": looping..."); + Thread.sleep(500); + } + // stop(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void start() throws Exception { + // TODO send a START_SYNC command to the discovery tool + // or fallback to START if not available + } + + @Override + public void stop() throws Exception { + // TODO send a STOP to the discovery + } + + @Override + public List listDiscoveredBoards() { + // TODO return the ports discovered so far + final List empty = new ArrayList<>(); + return empty; + } + + @Override + public List listDiscoveredBoards(boolean complete) { + // XXX: parameter "complete "is really needed? + // should be checked on all existing discoveries + + // TODO + final List empty = new ArrayList<>(); + return empty; + } + + @Override + public String toString() { + return discoveryName; + } +} diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 7ab457dcf..0a5876971 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -223,7 +223,7 @@ public class BaseNoGui { public static DiscoveryManager getDiscoveryManager() { if (discoveryManager == null) { - discoveryManager = new DiscoveryManager(); + discoveryManager = new DiscoveryManager(packages); } return discoveryManager; } @@ -506,7 +506,7 @@ public class BaseNoGui { } if (discoveryManager == null) { - discoveryManager = new DiscoveryManager(); + discoveryManager = new DiscoveryManager(packages); } } From f5bf6e5e7aad5349ee8807c55765f331f829faaa Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 28 Sep 2018 18:01:37 -0700 Subject: [PATCH 02/28] Add BoardPort copy constructor --- arduino-core/src/cc/arduino/packages/BoardPort.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index 0e85ffe13..bcab85384 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -47,6 +47,18 @@ public class BoardPort { this.prefs = new PreferencesMap(); } + public BoardPort(BoardPort bp) { + prefs = new PreferencesMap(); + // TODO: copy bp.prefs to prefs + address = bp.address; + protocol = bp.protocol; + boardName = bp.boardName; + vid = bp.vid; + pid = bp.pid; + iserial = bp.iserial; + label = bp.label; + } + public String getAddress() { return address; } From 5ba56abc8015ee865dd3551c099bc1c884b9525f Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 28 Sep 2018 18:04:35 -0700 Subject: [PATCH 03/28] Initial PluggableDiscovery using BoardPort for JSON --- .../discoverers/PluggableDiscovery.java | 150 +++++++++++++++--- 1 file changed, 131 insertions(+), 19 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 8bd435087..729b060e6 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -30,66 +30,178 @@ package cc.arduino.packages.discoverers; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; +import java.io.InputStream; +import java.io.OutputStream; import cc.arduino.packages.BoardPort; import cc.arduino.packages.Discovery; import processing.app.legacy.PApplet; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; + public class PluggableDiscovery implements Discovery { - private String discoveryName; + private final String discoveryName; + private final String[] cmd; + private final List portList; + private Process program=null; + private Thread pollingThread; public PluggableDiscovery(String discoveryName, String[] cmd) { + this.cmd = cmd; this.discoveryName = discoveryName; + portList = new LinkedList<>(); System.out.println("Starting: " + PApplet.join(cmd, " ")); } @Override public void run() { - // TODO this method is started as a new thread, it will constantly - // communicate with the discovery tool and keep track of the discovered - // port to be returned from listDiscoveredBoard() + // this method is started as a new thread, it will constantly listen + // to the discovery tool and keep track of the discovered ports try { start(); - while (true) { // TODO: Find a better way to terminate discovery - System.out.println(discoveryName + ": looping..."); - Thread.sleep(500); + InputStream input = program.getInputStream(); + JsonFactory factory = new JsonFactory(); + JsonParser parser = factory.createParser(input); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + while (program != null && program.isAlive()) { + BoardPort port = mapper.readValue(parser, BoardPort.class); + if (port != null) { + System.out.println(discoveryName + " received json"); + // + // TODO: check for START_SYNC not supported, call startPolling() + // + update(port); + } } - // stop(); + System.out.println("thread exit normally"); } catch (InterruptedException e) { + System.out.println("thread exit by interrupt"); e.printStackTrace(); } catch (Exception e) { + System.out.println("thread exit other exception"); e.printStackTrace(); } + try { + stop(); + } catch (Exception e) { + } } @Override public void start() throws Exception { - // TODO send a START_SYNC command to the discovery tool - // or fallback to START if not available + System.out.println(discoveryName + ": start"); + try { + program = Runtime.getRuntime().exec(cmd); + } catch (Exception e) { + program = null; + return; + } + write("START_SYNC\n"); + pollingThread = null; + } + + private void startPolling() { + // Discovery tools not supporting START_SYNC require a periodic + // LIST command. A second thread is created to send these + // commands, while the run() thread above listens for the + // discovery tool output. + write("START\n"); + Thread pollingThread = new Thread() { + public void run() { + try { + while (program != null && program.isAlive()) { + write("LIST\n"); + sleep(2500); + } + } catch (Exception e) { + } + } + }; + pollingThread.start(); } @Override public void stop() throws Exception { - // TODO send a STOP to the discovery + if (pollingThread != null) { + pollingThread.interrupt(); + pollingThread = null; + } + write("STOP\n"); + if (program != null) { + program.destroy(); + program = null; + } + } + + private void write(String command) { + if (program != null && program.isAlive()) { + OutputStream out = program.getOutputStream(); + try { + out.write(command.getBytes()); + out.flush(); + } catch (Exception e) { + } + } + } + + private synchronized void update(BoardPort port) { + // Update the list of discovered ports, which may involve + // adding a new port, replacing the info for a previously + // discovered port, or removing a port. This function + // must be synchronized with listDiscoveredBoards(), to + // avoid changing the list while it's being accessed by + // another thread. + String address = port.getAddress(); + if (address == null) { + return; // address is required + } + for (BoardPort bp : portList) { + if (address.equals(bp.getAddress())) { + // if address already on the list, discard old info + portList.remove(bp); + } + } + if (port.isOnline()) { + if (port.getLabel() == null) { + // if no label, use address + port.setLabel(address); + } + if (port.getProtocol() == null) { + // if no protocol, assume serial + port.setProtocol("serial"); + } + portList.add(port); + } } @Override - public List listDiscoveredBoards() { - // TODO return the ports discovered so far - final List empty = new ArrayList<>(); - return empty; + public synchronized List listDiscoveredBoards() { + // return the ports discovered so far. Because the list of + // ports may change at any moment, a copy of the list is + // returned for use by the rest of the IDE. This copy + // operation must be synchronized with update() to assure + // a clean copy. + final List portListCopy = new ArrayList<>(); + for (BoardPort bp : portList) { + //portListCopy.add(new BoardPort(bp)); + portListCopy.add(bp); + } + return portListCopy; } @Override public List listDiscoveredBoards(boolean complete) { // XXX: parameter "complete "is really needed? // should be checked on all existing discoveries - - // TODO - final List empty = new ArrayList<>(); - return empty; + return listDiscoveredBoards(); } @Override From b6066573b9f56ce0f37c9778d5ed65a5da78b0aa Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Sat, 29 Sep 2018 00:07:37 -0700 Subject: [PATCH 04/28] PluggableDiscovery check for START_SYNC not supported --- .../discoverers/PluggableDiscovery.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 729b060e6..d4967c257 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -56,7 +56,7 @@ public class PluggableDiscovery implements Discovery { this.cmd = cmd; this.discoveryName = discoveryName; portList = new LinkedList<>(); - System.out.println("Starting: " + PApplet.join(cmd, " ")); + System.out.println(discoveryName + ": Starting: " + PApplet.join(cmd, " ")); } @Override @@ -74,19 +74,25 @@ public class PluggableDiscovery implements Discovery { while (program != null && program.isAlive()) { BoardPort port = mapper.readValue(parser, BoardPort.class); if (port != null) { - System.out.println(discoveryName + " received json"); - // - // TODO: check for START_SYNC not supported, call startPolling() - // - update(port); + System.out.println(discoveryName + ": received json"); + String address = port.getAddress(); + if (address != null) { + if (address.equals("Error: START_SYNC not supported")) { + if (pollingThread == null) { + startPolling(); + } + } else { + update(port); + } + } } } - System.out.println("thread exit normally"); + System.out.println(discoveryName + ": thread exit normally"); } catch (InterruptedException e) { - System.out.println("thread exit by interrupt"); + System.out.println(discoveryName + ": thread exit by interrupt"); e.printStackTrace(); } catch (Exception e) { - System.out.println("thread exit other exception"); + System.out.println(discoveryName + ": thread exit other exception"); e.printStackTrace(); } try { @@ -160,9 +166,6 @@ public class PluggableDiscovery implements Discovery { // avoid changing the list while it's being accessed by // another thread. String address = port.getAddress(); - if (address == null) { - return; // address is required - } for (BoardPort bp : portList) { if (address.equals(bp.getAddress())) { // if address already on the list, discard old info @@ -191,8 +194,7 @@ public class PluggableDiscovery implements Discovery { // a clean copy. final List portListCopy = new ArrayList<>(); for (BoardPort bp : portList) { - //portListCopy.add(new BoardPort(bp)); - portListCopy.add(bp); + portListCopy.add(new BoardPort(bp)); } return portListCopy; } From e029acc6990d3476d68bab0a68a03945d795b364 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Mon, 1 Oct 2018 13:33:19 -0700 Subject: [PATCH 05/28] Add PluggableDiscoveryMessage for BoardPort change metadata --- .../discoverers/PluggableDiscovery.java | 17 ++++---- .../PluggableDiscoveryMessage.java | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index d4967c257..d2c09b874 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -72,17 +72,17 @@ public class PluggableDiscovery implements Discovery { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); while (program != null && program.isAlive()) { - BoardPort port = mapper.readValue(parser, BoardPort.class); - if (port != null) { + PluggableDiscoveryMessage msg = mapper.readValue(parser, PluggableDiscoveryMessage.class); + if (msg != null) { System.out.println(discoveryName + ": received json"); - String address = port.getAddress(); - if (address != null) { - if (address.equals("Error: START_SYNC not supported")) { + String event = msg.getEventType(); + if (event != null) { + if (event.equals("Error: START_SYNC not supported")) { if (pollingThread == null) { startPolling(); } } else { - update(port); + update(msg); } } } @@ -158,7 +158,7 @@ public class PluggableDiscovery implements Discovery { } } - private synchronized void update(BoardPort port) { + private synchronized void update(PluggableDiscoveryMessage port) { // Update the list of discovered ports, which may involve // adding a new port, replacing the info for a previously // discovered port, or removing a port. This function @@ -166,13 +166,14 @@ public class PluggableDiscovery implements Discovery { // avoid changing the list while it's being accessed by // another thread. String address = port.getAddress(); + if (address == null) return; // address required for "add" & "remove" for (BoardPort bp : portList) { if (address.equals(bp.getAddress())) { // if address already on the list, discard old info portList.remove(bp); } } - if (port.isOnline()) { + if (port.getEventType().equals("add")) { if (port.getLabel() == null) { // if no label, use address port.setLabel(address); diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java new file mode 100644 index 000000000..270739286 --- /dev/null +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java @@ -0,0 +1,39 @@ +/* + * 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 2018 Arduino SA (http://www.arduino.cc/) + */ + +package cc.arduino.packages.discoverers; +import cc.arduino.packages.BoardPort; + +public class PluggableDiscoveryMessage extends BoardPort { + private String eventType; // "add", "remove", "Error: START_SYNC not supported" + public String getEventType() { + return eventType; + } +} + From 05092bf17ffada129509cc6652d384922525bf2b Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Mon, 1 Oct 2018 15:29:17 -0700 Subject: [PATCH 06/28] Move BoardPort fixed fields into prefs --- .../src/cc/arduino/packages/BoardPort.java | 46 +++++++++++-------- .../discoverers/PluggableDiscovery.java | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index bcab85384..95476f478 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -33,30 +33,24 @@ import processing.app.helpers.PreferencesMap; public class BoardPort { - private String address; - private String protocol; + private String address; // unique name for this port, used by Preferences + private String protocol; // how to communicate, used for Ports menu sections private String boardName; - private String vid; - private String pid; - private String iserial; - private String label; - private final PreferencesMap prefs; - private boolean online; + private String label; // friendly name shown in Ports menu + private final PreferencesMap prefs; // "vendorId", "productId", "serialNumber" + private boolean online; // used by SerialBoardsLister (during upload??) public BoardPort() { this.prefs = new PreferencesMap(); } public BoardPort(BoardPort bp) { - prefs = new PreferencesMap(); - // TODO: copy bp.prefs to prefs + prefs = new PreferencesMap(bp.prefs); address = bp.address; protocol = bp.protocol; boardName = bp.boardName; - vid = bp.vid; - pid = bp.pid; - iserial = bp.iserial; label = bp.label; + online = bp.online; } public String getAddress() { @@ -104,27 +98,39 @@ public class BoardPort { } public void setVIDPID(String vid, String pid) { - this.vid = vid; - this.pid = pid; + if (vid == null) { + prefs.remove("vendorId"); + } else { + prefs.put("vendorId", vid); + } + if (pid == null) { + prefs.remove("productId"); + } else { + prefs.put("productId", pid); + } } public String getVID() { - return vid; + return prefs.get("vendorId"); } public String getPID() { - return pid; + return prefs.get("productId"); } public void setISerial(String iserial) { - this.iserial = iserial; + if (iserial == null) { + prefs.remove("serialNumber"); + } else { + prefs.put("serialNumber", iserial); + } } public String getISerial() { - return iserial; + return prefs.get("serialNumber"); } @Override public String toString() { - return this.address+"_"+this.vid+"_"+this.pid; + return this.address+"_"+getVID()+"_"+getPID(); } } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index d2c09b874..1c66716ae 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -74,7 +74,7 @@ public class PluggableDiscovery implements Discovery { while (program != null && program.isAlive()) { PluggableDiscoveryMessage msg = mapper.readValue(parser, PluggableDiscoveryMessage.class); if (msg != null) { - System.out.println(discoveryName + ": received json"); + System.out.println(discoveryName + ": received json: vid=" + msg.getVID() + ", pid=" + msg.getPID() + ", sernum=" + msg.getISerial()); String event = msg.getEventType(); if (event != null) { if (event.equals("Error: START_SYNC not supported")) { From d7143d6859b6f4c9ab4a23824829834f7e017575 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Tue, 2 Oct 2018 17:08:43 -0700 Subject: [PATCH 07/28] Add BoardPort identificationPrefs and searchMatchingBoard --- .../src/cc/arduino/packages/BoardPort.java | 42 +++++++++++++++++++ .../discoverers/PluggableDiscovery.java | 16 ++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index 95476f478..c71ac8aaa 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -29,6 +29,10 @@ package cc.arduino.packages; +import processing.app.BaseNoGui; +import processing.app.debug.TargetBoard; +import processing.app.debug.TargetPackage; +import processing.app.debug.TargetPlatform; import processing.app.helpers.PreferencesMap; public class BoardPort { @@ -37,15 +41,18 @@ public class BoardPort { private String protocol; // how to communicate, used for Ports menu sections private String boardName; private String label; // friendly name shown in Ports menu + private final PreferencesMap identificationPrefs; // data to match with boards.txt private final PreferencesMap prefs; // "vendorId", "productId", "serialNumber" private boolean online; // used by SerialBoardsLister (during upload??) public BoardPort() { this.prefs = new PreferencesMap(); + this.identificationPrefs = new PreferencesMap(); } public BoardPort(BoardPort bp) { prefs = new PreferencesMap(bp.prefs); + identificationPrefs = new PreferencesMap(bp.identificationPrefs); address = bp.address; protocol = bp.protocol; boardName = bp.boardName; @@ -133,4 +140,39 @@ public class BoardPort { public String toString() { return this.address+"_"+getVID()+"_"+getPID(); } + + // Search for the board which matches identificationPrefs. + // If found, boardName is set to the name from boards.txt + // and the board is returned. If not found, null is returned. + public TargetBoard searchMatchingBoard() { + if (identificationPrefs.isEmpty()) return null; + for (TargetPackage targetPackage : BaseNoGui.packages.values()) { + for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) { + for (TargetBoard board : targetPlatform.getBoards().values()) { + if (matchesIdentificationPrefs(board)) { + setBoardName(board.getName()); + return board; + } + } + } + } + return null; + } + // Check whether a board matches all identificationPrefs fields + private boolean matchesIdentificationPrefs(TargetBoard board) { + for (String key : identificationPrefs.keySet()) { + if (!matchesIdentificationPref(board, key)) return false; + } + return true; + } + // Check whether a board matches a single identificationPrefs field + private boolean matchesIdentificationPref(TargetBoard board, String key) { + String value = identificationPrefs.get(key); + if (value == null) return false; + for (String property : board.getPreferences().subTree(key).values()) { + if (property.equalsIgnoreCase(value)) return true; + } + return false; + } + } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 1c66716ae..899a3c7e2 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -43,6 +43,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; public class PluggableDiscovery implements Discovery { @@ -69,6 +71,8 @@ public class PluggableDiscovery implements Discovery { JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createParser(input); ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); while (program != null && program.isAlive()) { @@ -82,6 +86,9 @@ public class PluggableDiscovery implements Discovery { startPolling(); } } else { + if (event.equals("add")) { + msg.searchMatchingBoard(); + } update(msg); } } @@ -175,8 +182,13 @@ public class PluggableDiscovery implements Discovery { } if (port.getEventType().equals("add")) { if (port.getLabel() == null) { - // if no label, use address - port.setLabel(address); + // if no label, use address & name, or just address if no name + String name = port.getBoardName(); + if (name == null) { + port.setLabel(address); + } else { + port.setLabel(address + " (" + name + ")"); + } } if (port.getProtocol() == null) { // if no protocol, assume serial From 8d6fa726671edeb0e91b7dbc349a43b79dd4c89a Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 4 Oct 2018 11:08:16 +0200 Subject: [PATCH 08/28] Removing fixed fields in BoardPort --- app/src/processing/app/Editor.java | 6 ++-- .../src/cc/arduino/packages/BoardPort.java | 34 +------------------ .../discoverers/PluggableDiscovery.java | 2 +- .../serial/SerialBoardsLister.java | 11 +++--- 4 files changed, 10 insertions(+), 43 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index e0abd62e5..8b0989445 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2392,9 +2392,9 @@ public class Editor extends JFrame implements RunnerListener { for (BoardPort port : ports) { if (port.getAddress().equals(selectedPort)) { label = port.getBoardName(); - vid = port.getVID(); - pid = port.getPID(); - iserial = port.getISerial(); + vid = port.getPrefs().get("vid"); + pid = port.getPrefs().get("pid"); + iserial = port.getPrefs().get("iserial"); protocol = port.getProtocol(); found = true; break; diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index c71ac8aaa..71d713d4e 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -104,41 +104,9 @@ public class BoardPort { return online; } - public void setVIDPID(String vid, String pid) { - if (vid == null) { - prefs.remove("vendorId"); - } else { - prefs.put("vendorId", vid); - } - if (pid == null) { - prefs.remove("productId"); - } else { - prefs.put("productId", pid); - } - } - - public String getVID() { - return prefs.get("vendorId"); - } - - public String getPID() { - return prefs.get("productId"); - } - - public void setISerial(String iserial) { - if (iserial == null) { - prefs.remove("serialNumber"); - } else { - prefs.put("serialNumber", iserial); - } - } - public String getISerial() { - return prefs.get("serialNumber"); - } - @Override public String toString() { - return this.address+"_"+getVID()+"_"+getPID(); + return this.address; } // Search for the board which matches identificationPrefs. diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 899a3c7e2..4c5325be2 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -78,7 +78,7 @@ public class PluggableDiscovery implements Discovery { while (program != null && program.isAlive()) { PluggableDiscoveryMessage msg = mapper.readValue(parser, PluggableDiscoveryMessage.class); if (msg != null) { - System.out.println(discoveryName + ": received json: vid=" + msg.getVID() + ", pid=" + msg.getPID() + ", sernum=" + msg.getISerial()); + System.out.println(discoveryName + ": received json: " + msg.getPrefs()); String event = msg.getEventType(); if (event != null) { if (event.equals("Error: START_SYNC not supported")) { 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 d055a921a..08eeff99f 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -136,16 +136,13 @@ public class SerialBoardsLister extends TimerTask { if (boardData != null) { boardPort.getPrefs().put("vid", boardData.get("vid").toString()); boardPort.getPrefs().put("pid", boardData.get("pid").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"); @@ -158,12 +155,14 @@ public class SerialBoardsLister extends TimerTask { } } else { if (!parts[1].equals("0000")) { - boardPort.setVIDPID(parts[1], parts[2]); + boardPort.getPrefs().put("vid", parts[1]); + boardPort.getPrefs().put("pid", parts[2]); // ask Cloud API to match the board with known VID/PID pair platform.getBoardWithMatchingVidPidFromCloud(parts[1], parts[2]); } else { - boardPort.setVIDPID("0000", "0000"); - boardPort.setISerial(""); + boardPort.getPrefs().put("vid", "0000"); + boardPort.getPrefs().put("pid", "0000"); + boardPort.getPrefs().put("iserial", ""); } } From 3ccb2d97e14cd96b2330626fe3ad6597234d849c Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 4 Oct 2018 13:07:10 +0200 Subject: [PATCH 09/28] Merged SerialDiscovery and SerialBoardLister They perform basically the same task, SerialDiscovery just used to proxy the calls to SerialBoardLister --- .../cc/arduino/packages/DiscoveryManager.java | 2 +- .../packages/discoverers/SerialDiscovery.java | 103 ------------------ ...BoardsLister.java => SerialDiscovery.java} | 89 +++++++++++---- 3 files changed, 70 insertions(+), 124 deletions(-) delete mode 100644 arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java rename arduino-core/src/cc/arduino/packages/discoverers/serial/{SerialBoardsLister.java => SerialDiscovery.java} (74%) diff --git a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java index f8b239401..47f502396 100644 --- a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java +++ b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java @@ -37,8 +37,8 @@ import java.util.List; import java.util.Map; import cc.arduino.packages.discoverers.PluggableDiscovery; +import cc.arduino.packages.discoverers.serial.SerialDiscovery; import cc.arduino.packages.discoverers.NetworkDiscovery; -import cc.arduino.packages.discoverers.SerialDiscovery; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; import processing.app.helpers.PreferencesMap; diff --git a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java deleted file mode 100644 index 4de78552c..000000000 --- a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java +++ /dev/null @@ -1,103 +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; - -import cc.arduino.packages.BoardPort; -import cc.arduino.packages.Discovery; -import cc.arduino.packages.discoverers.serial.SerialBoardsLister; - -import java.util.LinkedList; -import java.util.List; -import java.util.Timer; - -public class SerialDiscovery implements Discovery, Runnable { - - private Timer serialBoardsListerTimer; - private final List serialBoardPorts; - private SerialBoardsLister serialBoardsLister = new SerialBoardsLister(this); - - public SerialDiscovery() { - this.serialBoardPorts = new LinkedList<>(); - } - - @Override - public List listDiscoveredBoards() { - return getSerialBoardPorts(false); - } - - @Override - 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) { - 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 run() { - start(); - } - - @Override - public void start() { - this.serialBoardsListerTimer = new Timer(SerialBoardsLister.class.getName()); - serialBoardsLister.start(serialBoardsListerTimer); - } - - @Override - public void stop() { - this.serialBoardsListerTimer.purge(); - } -} diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java similarity index 74% rename from arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java rename to arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java index 08eeff99f..46ddc10e7 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java @@ -29,29 +29,86 @@ package cc.arduino.packages.discoverers.serial; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + import cc.arduino.packages.BoardPort; -import cc.arduino.packages.discoverers.SerialDiscovery; +import cc.arduino.packages.Discovery; import processing.app.BaseNoGui; import processing.app.Platform; import processing.app.debug.TargetBoard; -import java.util.*; +public class SerialDiscovery implements Discovery, Runnable { -public class SerialBoardsLister extends TimerTask { - - private final SerialDiscovery serialDiscovery; - private final List boardPorts = new LinkedList<>(); - private List oldPorts = new LinkedList<>(); + private Timer serialBoardsListerTimer; + private final List serialBoardPorts = new ArrayList<>(); + private final List boardPorts = new ArrayList<>(); + private final List oldPorts = new ArrayList<>(); public boolean uploadInProgress = false; public boolean pausePolling = false; private BoardPort oldUploadBoardPort = null; - public SerialBoardsLister(SerialDiscovery serialDiscovery) { - this.serialDiscovery = serialDiscovery; + + @Override + public List listDiscoveredBoards() { + return listDiscoveredBoards(false); } - public void start(Timer timer) { - timer.schedule(this, 0, 1000); + @Override + public List listDiscoveredBoards(boolean complete) { + if (complete) { + return new ArrayList<>(serialBoardPorts); + } + List onlineBoardPorts = new ArrayList<>(); + for (BoardPort port : serialBoardPorts) { + if (port.isOnline() == true) { + onlineBoardPorts.add(port); + } + } + return onlineBoardPorts; + } + + public void setSerialBoardPorts(List newSerialBoardPorts) { + serialBoardPorts.clear(); + serialBoardPorts.addAll(newSerialBoardPorts); + } + + public void forceRefresh() { + retriggerDiscovery(false); + } + + public void setUploadInProgress(boolean param) { + uploadInProgress = param; + } + + public void pausePolling(boolean param) { + pausePolling = param; + } + + @Override + public void run() { + start(); + } + + @Override + public void start() { + serialBoardsListerTimer = new Timer(SerialDiscovery.class.getName()); + serialBoardsListerTimer.schedule(new TimerTask() { + @Override + public void run() { + if (BaseNoGui.packages != null) { + retriggerDiscovery(true); + } + } + }, 0, 1000); + } + + @Override + public void stop() { + serialBoardsListerTimer.cancel(); } public synchronized void retriggerDiscovery(boolean polled) { @@ -171,14 +228,6 @@ public class SerialBoardsLister extends TimerTask { boardPorts.add(boardPort); } } - serialDiscovery.setSerialBoardPorts(boardPorts); - } - - @Override - public void run() { - if (BaseNoGui.packages == null) { - return; - } - retriggerDiscovery(true); + setSerialBoardPorts(boardPorts); } } From 80fb9a0b38694e77d430c7cdfb5db164e57707c6 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 4 Oct 2018 13:11:51 +0200 Subject: [PATCH 10/28] Optimized forceRefresh() method by removing redundant boolean paramater --- .../discoverers/serial/SerialDiscovery.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java index 46ddc10e7..a7ff00e4d 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java @@ -76,10 +76,6 @@ public class SerialDiscovery implements Discovery, Runnable { serialBoardPorts.addAll(newSerialBoardPorts); } - public void forceRefresh() { - retriggerDiscovery(false); - } - public void setUploadInProgress(boolean param) { uploadInProgress = param; } @@ -99,9 +95,9 @@ public class SerialDiscovery implements Discovery, Runnable { serialBoardsListerTimer.schedule(new TimerTask() { @Override public void run() { - if (BaseNoGui.packages != null) { - retriggerDiscovery(true); - } + if (BaseNoGui.packages != null && !pausePolling) { + forceRefresh(); + } } }, 0, 1000); } @@ -111,16 +107,12 @@ public class SerialDiscovery implements Discovery, Runnable { serialBoardsListerTimer.cancel(); } - public synchronized void retriggerDiscovery(boolean polled) { + public synchronized void forceRefresh() { Platform platform = BaseNoGui.getPlatform(); if (platform == null) { return; } - if (polled && pausePolling) { - return; - } - List ports = platform.listSerials(); if (ports.equals(oldPorts)) { return; From 5bc96652e612d57dfc5f32ac68b682ca838cb4dc Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 4 Oct 2018 13:40:05 +0200 Subject: [PATCH 11/28] Slightly optimized method by removing redundant boolean flag --- .../packages/discoverers/serial/SerialDiscovery.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java index a7ff00e4d..f589a0195 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java @@ -162,19 +162,18 @@ public class SerialDiscovery implements Discovery, Runnable { 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) { + if (boardPort == null) { boardPort = new BoardPort(); + boardPorts.add(boardPort); } boardPort.setAddress(port); boardPort.setProtocol("serial"); @@ -216,9 +215,6 @@ public class SerialDiscovery implements Discovery, Runnable { } boardPort.setLabel(label); - if (!updatingInfos) { - boardPorts.add(boardPort); - } } setSerialBoardPorts(boardPorts); } From ec4787a92b849ca1ed6baeabc68e15ceedd3b1dc Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 4 Oct 2018 18:34:16 +0200 Subject: [PATCH 12/28] Fixed board identification in BoardPort --- .../src/cc/arduino/packages/BoardPort.java | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index 71d713d4e..ccc01db31 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -88,6 +88,10 @@ public class BoardPort { return prefs; } + public PreferencesMap getIdentificationPrefs() { + return identificationPrefs; + } + public void setLabel(String label) { this.label = label; } @@ -117,7 +121,7 @@ public class BoardPort { for (TargetPackage targetPackage : BaseNoGui.packages.values()) { for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) { for (TargetBoard board : targetPlatform.getBoards().values()) { - if (matchesIdentificationPrefs(board)) { + if (matchesBoard(board)) { setBoardName(board.getName()); return board; } @@ -126,21 +130,44 @@ public class BoardPort { } return null; } - // Check whether a board matches all identificationPrefs fields - private boolean matchesIdentificationPrefs(TargetBoard board) { - for (String key : identificationPrefs.keySet()) { - if (!matchesIdentificationPref(board, key)) return false; + + public boolean matchesBoard(TargetBoard board) { + PreferencesMap identificationProps = getIdentificationPrefs(); + PreferencesMap boardProps = board.getPreferences(); + + // Identification properties are defined in boards.txt with a ".N" suffix + // for example: + // + // uno.name=Arduino/Genuino Uno + // uno.vid.0=0x2341 + // uno.pid.0=0x0043 + // uno.vid.1=0x2341 + // uno.pid.1=0x0001 + // uno.vid.2=0x2A03 + // uno.pid.2=0x0043 + // uno.vid.3=0x2341 + // uno.pid.3=0x0243 + // + // so we must search starting from suffix ".0" and increasing until we + // found a match or the board has no more identification properties defined + + for (int suffix = 0;; suffix++) { + boolean found = true; + for (String prop : identificationProps.keySet()) { + String value = identificationProps.get(prop); + prop += "." + suffix; + if (!boardProps.containsKey(prop)) { + return false; + } + if (!value.equalsIgnoreCase(boardProps.get(prop))) { + found = false; + break; + } + } + if (found) { + return true; + } } - return true; - } - // Check whether a board matches a single identificationPrefs field - private boolean matchesIdentificationPref(TargetBoard board, String key) { - String value = identificationPrefs.get(key); - if (value == null) return false; - for (String property : board.getPreferences().subTree(key).values()) { - if (property.equalsIgnoreCase(value)) return true; - } - return false; } } From 9ba172b0db8ba02bfc0e0ac6f26f400eedcdd5e9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 23 Nov 2018 12:35:59 +0100 Subject: [PATCH 13/28] Show BoardName.boardName field in 'Ports' menu ...instead of putting it into the 'label' field during discovery. --- app/src/processing/app/Editor.java | 11 ++++++++--- .../packages/discoverers/serial/SerialDiscovery.java | 3 --- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 8b0989445..fc9714b16 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -1041,18 +1041,23 @@ public class Editor extends JFrame implements RunnerListener { private BoardPort port; public BoardPortJCheckBoxMenuItem(BoardPort port) { - super(port.getLabel()); + super(); + this.port = port; + setText(toString()); addActionListener(e -> { selectSerialPort(port.getAddress()); base.onBoardOrPortChange(); }); - this.port = port; } @Override public String toString() { // This is required for serialPrompt() - return port.getLabel(); + String label = port.getLabel(); + if (port.getBoardName() != null && !port.getBoardName().isEmpty()) { + label += " (" + port.getBoardName() + ")"; + } + return label; } } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java index f589a0195..3d5fb2fd7 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialDiscovery.java @@ -196,9 +196,6 @@ public class SerialDiscovery implements Discovery, Runnable { TargetBoard board = (TargetBoard) boardData.get("board"); if (board != null) { String boardName = board.getName(); - if (boardName != null) { - label += " (" + boardName + ")"; - } boardPort.setBoardName(boardName); } } else { From cfd3cf2b276b5d607d055112c71ef52408c2058e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 23 Nov 2018 18:34:52 +0100 Subject: [PATCH 14/28] Use correctly the setBoardName() method in NetworkDiscovery --- .../cc/arduino/packages/discoverers/NetworkDiscovery.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java index 713956690..502193153 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java @@ -113,15 +113,12 @@ public class NetworkDiscovery implements Discovery, ServiceListener, Runnable { String label = name + " at " + address; if (board != null && BaseNoGui.packages != null) { String boardName = BaseNoGui.getPlatform().resolveDeviceByBoardID(BaseNoGui.packages, board); - if (boardName != null) { - label += " (" + boardName + ")"; - } + port.setBoardName(boardName); } else if (description != null) { label += " (" + description + ")"; } port.setAddress(address); - port.setBoardName(name); port.setProtocol("network"); port.setLabel(label); From c03a8bc175c827beff8226a4b1b36a7bf3993bb1 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 23 Nov 2018 18:35:27 +0100 Subject: [PATCH 15/28] Minor fix in indentation and style --- .../cc/arduino/packages/discoverers/NetworkDiscovery.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java index 502193153..8619a92f0 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java @@ -162,7 +162,7 @@ public class NetworkDiscovery implements Discovery, ServiceListener, Runnable { @Override public List listDiscoveredBoards() { - synchronized (reachableBoardPorts) { + synchronized (reachableBoardPorts) { return getBoardPortsDiscoveredWithJmDNS(); } } @@ -176,8 +176,8 @@ public class NetworkDiscovery implements Discovery, ServiceListener, Runnable { public void setReachableBoardPorts(List newReachableBoardPorts) { synchronized (reachableBoardPorts) { - this.reachableBoardPorts.clear(); - this.reachableBoardPorts.addAll(newReachableBoardPorts); + reachableBoardPorts.clear(); + reachableBoardPorts.addAll(newReachableBoardPorts); } } From 349af4b5cfa7410726ba4e163903c8d03f82170f Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 29 Nov 2018 15:40:10 +0100 Subject: [PATCH 16/28] Added BoardPort.protocolLabel and simplified port menu rendering --- app/src/processing/app/Editor.java | 57 +++++++++++-------- .../src/cc/arduino/packages/BoardPort.java | 9 +++ 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index fc9714b16..1cea8fea4 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -52,7 +52,6 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; @@ -147,9 +146,6 @@ public class Editor extends JFrame implements RunnerListener { } } - private final static List BOARD_PROTOCOLS_ORDER = Arrays.asList("serial", "network"); - private final static List BOARD_PROTOCOLS_ORDER_TRANSLATIONS = Arrays.asList(tr("Serial ports"), tr("Network ports")); - final Base base; // otherwise, if the window is resized with the message label @@ -1062,6 +1058,9 @@ public class Editor extends JFrame implements RunnerListener { } private void populatePortMenu() { + final List PROTOCOLS_ORDER = Arrays.asList("serial", "network"); + final List PROTOCOLS_LABELS = Arrays.asList(tr("Serial ports"), tr("Network ports")); + portMenu.removeAll(); String selectedPort = PreferencesData.get("serial.port"); @@ -1070,31 +1069,43 @@ public class Editor extends JFrame implements RunnerListener { ports = platform.filterPorts(ports, PreferencesData.getBoolean("serial.ports.showall")); - Collections.sort(ports, new Comparator() { - @Override - public int compare(BoardPort o1, BoardPort o2) { - return (BOARD_PROTOCOLS_ORDER.indexOf(o1.getProtocol()) - BOARD_PROTOCOLS_ORDER.indexOf(o2.getProtocol())) * 10 + - o1.getAddress().compareTo(o2.getAddress()); - } + ports.stream() // + .filter(port -> port.getProtocolLabel() == null || port.getProtocolLabel().isEmpty()) + .forEach(port -> { + int labelIdx = PROTOCOLS_ORDER.indexOf(port.getProtocol()); + if (labelIdx != -1) { + port.setProtocolLabel(PROTOCOLS_LABELS.get(labelIdx)); + } else { + port.setProtocolLabel(port.getProtocol()); + } + }); + + Collections.sort(ports, (port1, port2) -> { + String pr1 = port1.getProtocol(); + String pr2 = port2.getProtocol(); + int prIdx1 = PROTOCOLS_ORDER.contains(pr1) ? PROTOCOLS_ORDER.indexOf(pr1) : 999; + int prIdx2 = PROTOCOLS_ORDER.contains(pr2) ? PROTOCOLS_ORDER.indexOf(pr2) : 999; + int r = prIdx1 - prIdx2; + if (r != 0) + return r; + r = port1.getProtocolLabel().compareTo(port2.getProtocolLabel()); + if (r != 0) + return r; + return port1.getAddress().compareTo(port2.getAddress()); }); - String lastProtocol = null; - String lastProtocolTranslated; + String lastProtocol = ""; + String lastProtocolLabel = ""; for (BoardPort port : ports) { - if (lastProtocol == null || !port.getProtocol().equals(lastProtocol)) { - if (lastProtocol != null) { + if (!port.getProtocol().equals(lastProtocol) || !port.getProtocolLabel().equals(lastProtocolLabel)) { + if (!lastProtocol.isEmpty()) { portMenu.addSeparator(); } lastProtocol = port.getProtocol(); - - if (BOARD_PROTOCOLS_ORDER.indexOf(port.getProtocol()) != -1) { - lastProtocolTranslated = BOARD_PROTOCOLS_ORDER_TRANSLATIONS.get(BOARD_PROTOCOLS_ORDER.indexOf(port.getProtocol())); - } else { - lastProtocolTranslated = port.getProtocol(); - } - JMenuItem lastProtocolMenuItem = new JMenuItem(tr(lastProtocolTranslated)); - lastProtocolMenuItem.setEnabled(false); - portMenu.add(lastProtocolMenuItem); + lastProtocolLabel = port.getProtocolLabel(); + JMenuItem item = new JMenuItem(tr(lastProtocolLabel)); + item.setEnabled(false); + portMenu.add(item); } String address = port.getAddress(); diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index ccc01db31..3068f059c 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -39,6 +39,7 @@ public class BoardPort { private String address; // unique name for this port, used by Preferences private String protocol; // how to communicate, used for Ports menu sections + private String protocolLabel; // protocol extended name to display on GUI private String boardName; private String label; // friendly name shown in Ports menu private final PreferencesMap identificationPrefs; // data to match with boards.txt @@ -76,6 +77,14 @@ public class BoardPort { this.protocol = protocol; } + public String getProtocolLabel() { + return protocolLabel; + } + + public void setProtocolLabel(String protocolLabel) { + this.protocolLabel = protocolLabel; + } + public String getBoardName() { return boardName; } From 718621303493936da95148d132bc1ec431438ca9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 30 Nov 2018 10:52:27 +0100 Subject: [PATCH 17/28] Slightly changed pluggable discovery json parsing The json input is now parsed into a JsonTree that can probed for the 'eventType' node value so we can understand the type of message to decode to. --- .../discoverers/PluggableDiscovery.java | 191 ++++++++++++------ .../PluggableDiscoveryMessage.java | 12 +- 2 files changed, 137 insertions(+), 66 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 4c5325be2..beb66f028 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -29,36 +29,43 @@ package cc.arduino.packages.discoverers; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +import static processing.app.I18n.format; + import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import cc.arduino.packages.BoardPort; import cc.arduino.packages.Discovery; -import processing.app.legacy.PApplet; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import processing.app.PreferencesData; +import processing.app.helpers.StringUtils; public class PluggableDiscovery implements Discovery { private final String discoveryName; private final String[] cmd; - private final List portList; + private final List portList = new ArrayList<>(); private Process program=null; private Thread pollingThread; + private void debug(String x) { + if (PreferencesData.getBoolean("discovery.debug")) + System.out.println(discoveryName + ": " + x); + } + public PluggableDiscovery(String discoveryName, String[] cmd) { this.cmd = cmd; this.discoveryName = discoveryName; - portList = new LinkedList<>(); - System.out.println(discoveryName + ": Starting: " + PApplet.join(cmd, " ")); } @Override @@ -76,30 +83,23 @@ public class PluggableDiscovery implements Discovery { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); while (program != null && program.isAlive()) { - PluggableDiscoveryMessage msg = mapper.readValue(parser, PluggableDiscoveryMessage.class); - if (msg != null) { - System.out.println(discoveryName + ": received json: " + msg.getPrefs()); - String event = msg.getEventType(); - if (event != null) { - if (event.equals("Error: START_SYNC not supported")) { - if (pollingThread == null) { - startPolling(); - } - } else { - if (event.equals("add")) { - msg.searchMatchingBoard(); - } - update(msg); - } + JsonNode tree = mapper.readTree(parser); + if (tree == null) { + if (program != null && program.isAlive()) { + System.err.println(format("{0}: Invalid json message", discoveryName)); } + break; } + debug("Received json: " + tree); + + processJsonNode(mapper, tree); } - System.out.println(discoveryName + ": thread exit normally"); + debug("thread exit normally"); } catch (InterruptedException e) { - System.out.println(discoveryName + ": thread exit by interrupt"); + debug("thread exit by interrupt"); e.printStackTrace(); } catch (Exception e) { - System.out.println(discoveryName + ": thread exit other exception"); + debug("thread exit other exception"); e.printStackTrace(); } try { @@ -108,15 +108,89 @@ public class PluggableDiscovery implements Discovery { } } + private void processJsonNode(ObjectMapper mapper, JsonNode node) { + JsonNode eventTypeNode = node.get("eventType"); + if (eventTypeNode == null) { + System.err.println(format("{0}: Invalid message, missing eventType", discoveryName)); + return; + } + + switch (eventTypeNode.asText()) { + case "error": + try { + PluggableDiscoveryMessage msg = mapper.treeToValue(node, PluggableDiscoveryMessage.class); + debug("error: " + msg.getMessage()); + if (msg.getMessage().contains("START_SYNC")) { + startPolling(); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return; + + case "list": + JsonNode portsNode = node.get("ports"); + if (portsNode == null) { + System.err.println(format("{0}: Invalid message, missing ports list", discoveryName)); + return; + } + if (!portsNode.isArray()) { + System.err.println(format("{0}: Invalid message, ports list should be an array", discoveryName)); + return; + } + + portList.clear(); + portsNode.forEach(portNode -> { + try { + BoardPort port = mapper.treeToValue(portNode, BoardPort.class); + port.searchMatchingBoard(); + addOrUpdate(port); + } catch (JsonProcessingException e) { + System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); + e.printStackTrace(); + } + }); + return; + + // Messages for SYNC updates + + case "add": + try { + BoardPort port = mapper.treeToValue(node, BoardPort.class); + port.searchMatchingBoard(); + addOrUpdate(port); + } catch (JsonProcessingException e) { + System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); + e.printStackTrace(); + } + return; + + case "remove": + try { + BoardPort port = mapper.treeToValue(node, BoardPort.class); + remove(port); + } catch (JsonProcessingException e) { + System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); + e.printStackTrace(); + } + return; + + default: + debug("Invalid event: " + eventTypeNode.asText()); + return; + } + } + @Override public void start() throws Exception { - System.out.println(discoveryName + ": start"); try { + debug("Starting: " + StringUtils.join(cmd, " ")); program = Runtime.getRuntime().exec(cmd); } catch (Exception e) { program = null; return; } + debug("START_SYNC"); write("START_SYNC\n"); pollingThread = null; } @@ -126,11 +200,13 @@ public class PluggableDiscovery implements Discovery { // LIST command. A second thread is created to send these // commands, while the run() thread above listens for the // discovery tool output. + debug("START"); write("START\n"); Thread pollingThread = new Thread() { public void run() { try { while (program != null && program.isAlive()) { + debug("LIST"); write("LIST\n"); sleep(2500); } @@ -165,7 +241,7 @@ public class PluggableDiscovery implements Discovery { } } - private synchronized void update(PluggableDiscoveryMessage port) { + private synchronized void addOrUpdate(BoardPort port) { // Update the list of discovered ports, which may involve // adding a new port, replacing the info for a previously // discovered port, or removing a port. This function @@ -173,29 +249,24 @@ public class PluggableDiscovery implements Discovery { // avoid changing the list while it's being accessed by // another thread. String address = port.getAddress(); - if (address == null) return; // address required for "add" & "remove" - for (BoardPort bp : portList) { - if (address.equals(bp.getAddress())) { - // if address already on the list, discard old info - portList.remove(bp); - } - } - if (port.getEventType().equals("add")) { - if (port.getLabel() == null) { - // if no label, use address & name, or just address if no name - String name = port.getBoardName(); - if (name == null) { - port.setLabel(address); - } else { - port.setLabel(address + " (" + name + ")"); - } - } - if (port.getProtocol() == null) { - // if no protocol, assume serial - port.setProtocol("serial"); - } - portList.add(port); + if (address == null) + return; // address required for "add" & "remove" + + // if address already on the list, discard old info + portList.removeIf(bp -> address.equals(bp.getAddress())); + + // if no label, use address + if (port.getLabel() == null) { + port.setLabel(address); } + portList.add(port); + } + + private synchronized void remove(BoardPort port) { + String address = port.getAddress(); + if (address == null) + return; // address required for "add" & "remove" + portList.removeIf(bp -> address.equals(bp.getAddress())); } @Override @@ -205,18 +276,14 @@ public class PluggableDiscovery implements Discovery { // returned for use by the rest of the IDE. This copy // operation must be synchronized with update() to assure // a clean copy. - final List portListCopy = new ArrayList<>(); - for (BoardPort bp : portList) { - portListCopy.add(new BoardPort(bp)); - } - return portListCopy; + return new ArrayList<>(portList); } @Override public List listDiscoveredBoards(boolean complete) { // XXX: parameter "complete "is really needed? // should be checked on all existing discoveries - return listDiscoveredBoards(); + return new ArrayList<>(portList); } @Override diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java index 270739286..3a377d064 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscoveryMessage.java @@ -28,12 +28,16 @@ */ package cc.arduino.packages.discoverers; -import cc.arduino.packages.BoardPort; -public class PluggableDiscoveryMessage extends BoardPort { - private String eventType; // "add", "remove", "Error: START_SYNC not supported" +public class PluggableDiscoveryMessage { + private String eventType; // "add", "remove", "error" + private String message; // optional message, e.g. "START_SYNC not supported" + public String getEventType() { return eventType; } -} + public String getMessage() { + return message; + } +} From 8e9f0cfd76848056de012e01af2707d52c07ed51 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 30 Nov 2018 11:19:07 +0100 Subject: [PATCH 18/28] PluggableDiscovery: added a 'port' field in json messages The new format of 'add' and 'remove' actions is changed from: { "eventType": "add", "address": "/dev/ttyACM0", "label": "/dev/ttyACM0", "prefs": { "vendorId": "0x2341" "productId": "0x0043", "serialNumber": "85235353137351018160", }, "identificationPrefs": { "vid": "0x2341" "pid": "0x0043", }, "protocol": "serial", "protocolLabel": "Serial Port" } to: { "eventType": "add", "port": { "address": "/dev/ttyACM0", "label": "/dev/ttyACM0", "prefs": { "vendorId": "0x2341" "productId": "0x0043", "serialNumber": "85235353137351018160", }, "identificationPrefs": { "vid": "0x2341" "pid": "0x0043", }, "protocol": "serial", "protocolLabel": "Serial Port" } } --- .../cc/arduino/packages/discoverers/PluggableDiscovery.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index beb66f028..7123b6d40 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -156,7 +156,7 @@ public class PluggableDiscovery implements Discovery { case "add": try { - BoardPort port = mapper.treeToValue(node, BoardPort.class); + BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); port.searchMatchingBoard(); addOrUpdate(port); } catch (JsonProcessingException e) { @@ -167,7 +167,7 @@ public class PluggableDiscovery implements Discovery { case "remove": try { - BoardPort port = mapper.treeToValue(node, BoardPort.class); + BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); remove(port); } catch (JsonProcessingException e) { System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); From 4c188c9374a197fdad42704952ae894ec04750a9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 30 Nov 2018 12:03:15 +0100 Subject: [PATCH 19/28] PluggableDiscovery: Factored out method to umarshal BoardPort from JSON --- .../src/cc/arduino/packages/BoardPort.java | 2 +- .../discoverers/PluggableDiscovery.java | 39 ++++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index 3068f059c..1f5181b89 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -126,7 +126,7 @@ public class BoardPort { // If found, boardName is set to the name from boards.txt // and the board is returned. If not found, null is returned. public TargetBoard searchMatchingBoard() { - if (identificationPrefs.isEmpty()) return null; + if (identificationPrefs == null || identificationPrefs.isEmpty()) return null; for (TargetPackage targetPackage : BaseNoGui.packages.values()) { for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) { for (TargetBoard board : targetPlatform.getBoards().values()) { diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 7123b6d40..bbeabff20 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -141,13 +141,9 @@ public class PluggableDiscovery implements Discovery { portList.clear(); portsNode.forEach(portNode -> { - try { - BoardPort port = mapper.treeToValue(portNode, BoardPort.class); - port.searchMatchingBoard(); + BoardPort port = mapJsonNodeToBoardPort(mapper, node); + if (port != null) { addOrUpdate(port); - } catch (JsonProcessingException e) { - System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); - e.printStackTrace(); } }); return; @@ -155,23 +151,16 @@ public class PluggableDiscovery implements Discovery { // Messages for SYNC updates case "add": - try { - BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); - port.searchMatchingBoard(); - addOrUpdate(port); - } catch (JsonProcessingException e) { - System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); - e.printStackTrace(); + BoardPort addedPort = mapJsonNodeToBoardPort(mapper, node); + if (addedPort != null) { + addOrUpdate(addedPort); } return; case "remove": - try { - BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); - remove(port); - } catch (JsonProcessingException e) { - System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); - e.printStackTrace(); + BoardPort removedPort = mapJsonNodeToBoardPort(mapper, node); + if (removedPort != null) { + remove(removedPort); } return; @@ -181,6 +170,18 @@ public class PluggableDiscovery implements Discovery { } } + private BoardPort mapJsonNodeToBoardPort(ObjectMapper mapper, JsonNode node) { + try { + BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); + port.searchMatchingBoard(); + return port; + } catch (JsonProcessingException e) { + System.err.println(format("{0}: Invalid BoardPort message", discoveryName)); + e.printStackTrace(); + return null; + } + } + @Override public void start() throws Exception { try { From 4ae740ad668749e9d5167f801f01e4077a742e73 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 30 Nov 2018 12:06:23 +0100 Subject: [PATCH 20/28] PluggableDiscovery: BoardPort.label sanity check in the correct place --- .../arduino/packages/discoverers/PluggableDiscovery.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index bbeabff20..9a6a4ba89 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -173,6 +173,10 @@ public class PluggableDiscovery implements Discovery { private BoardPort mapJsonNodeToBoardPort(ObjectMapper mapper, JsonNode node) { try { BoardPort port = mapper.treeToValue(node.get("port"), BoardPort.class); + // if no label, use address + if (port.getLabel() == null || port.getLabel().isEmpty()) { + port.setLabel(port.getAddress()); + } port.searchMatchingBoard(); return port; } catch (JsonProcessingException e) { @@ -256,10 +260,6 @@ public class PluggableDiscovery implements Discovery { // if address already on the list, discard old info portList.removeIf(bp -> address.equals(bp.getAddress())); - // if no label, use address - if (port.getLabel() == null) { - port.setLabel(address); - } portList.add(port); } From 7bc086a301bb4952ad3520d397d7a336e6bb8922 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 30 Nov 2018 12:09:34 +0100 Subject: [PATCH 21/28] PluggableDiscovery: correct synchronization on 'portList' access --- .../discoverers/PluggableDiscovery.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java index 9a6a4ba89..d37166699 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/PluggableDiscovery.java @@ -139,7 +139,9 @@ public class PluggableDiscovery implements Discovery { return; } - portList.clear(); + synchronized (portList) { + portList.clear(); + } portsNode.forEach(portNode -> { BoardPort port = mapJsonNodeToBoardPort(mapper, node); if (port != null) { @@ -246,45 +248,41 @@ public class PluggableDiscovery implements Discovery { } } - private synchronized void addOrUpdate(BoardPort port) { - // Update the list of discovered ports, which may involve - // adding a new port, replacing the info for a previously - // discovered port, or removing a port. This function - // must be synchronized with listDiscoveredBoards(), to - // avoid changing the list while it's being accessed by - // another thread. + private void addOrUpdate(BoardPort port) { String address = port.getAddress(); if (address == null) return; // address required for "add" & "remove" - // if address already on the list, discard old info - portList.removeIf(bp -> address.equals(bp.getAddress())); - - portList.add(port); + synchronized (portList) { + // if address already on the list, discard old info + portList.removeIf(bp -> address.equals(bp.getAddress())); + portList.add(port); + } } - private synchronized void remove(BoardPort port) { + private void remove(BoardPort port) { String address = port.getAddress(); if (address == null) return; // address required for "add" & "remove" - portList.removeIf(bp -> address.equals(bp.getAddress())); + synchronized (portList) { + portList.removeIf(bp -> address.equals(bp.getAddress())); + } } @Override - public synchronized List listDiscoveredBoards() { - // return the ports discovered so far. Because the list of - // ports may change at any moment, a copy of the list is - // returned for use by the rest of the IDE. This copy - // operation must be synchronized with update() to assure - // a clean copy. - return new ArrayList<>(portList); + public List listDiscoveredBoards() { + synchronized (portList) { + return new ArrayList<>(portList); + } } @Override public List listDiscoveredBoards(boolean complete) { // XXX: parameter "complete "is really needed? // should be checked on all existing discoveries - return new ArrayList<>(portList); + synchronized (portList) { + return new ArrayList<>(portList); + } } @Override From 6c50007e22499b5cc3a2d0b48696711d67ea2552 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 7 Dec 2018 12:36:09 +0100 Subject: [PATCH 22/28] Editor: renamed status bar field serialport -> port --- app/src/processing/app/Editor.java | 2 +- app/src/processing/app/EditorLineStatus.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 1cea8fea4..43e52da33 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2585,7 +2585,7 @@ public class Editor extends JFrame implements RunnerListener { lineStatus.setBoardName(boardPreferences.get("name")); else lineStatus.setBoardName("-"); - lineStatus.setSerialPort(PreferencesData.get("serial.port")); + lineStatus.setPort(PreferencesData.get("serial.port")); lineStatus.repaint(); } diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java index f71dd4573..4163370d2 100644 --- a/app/src/processing/app/EditorLineStatus.java +++ b/app/src/processing/app/EditorLineStatus.java @@ -51,7 +51,7 @@ public class EditorLineStatus extends JComponent { String text = ""; String name = ""; - String serialport = ""; + String port = ""; String serialnumber = ""; public EditorLineStatus() { @@ -92,13 +92,13 @@ public class EditorLineStatus extends JComponent { public void paintComponent(Graphics graphics) { Graphics2D g = Theme.setupGraphics2D(graphics); - if (name.isEmpty() && serialport.isEmpty()) { + if (name.isEmpty() && port.isEmpty()) { PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences(); if (boardPreferences != null) setBoardName(boardPreferences.get("name")); else setBoardName("-"); - setSerialPort(PreferencesData.get("serial.port")); + setPort(PreferencesData.get("serial.port")); } g.setColor(background); Dimension size = getSize(); @@ -112,8 +112,8 @@ public class EditorLineStatus extends JComponent { g.setColor(messageForeground); String statusText; - if (serialport != null && !serialport.isEmpty()) { - statusText = I18n.format(tr("{0} on {1}"), name, serialport); + if (port != null && !port.isEmpty()) { + statusText = I18n.format(tr("{0} on {1}"), name, port); } else { statusText = name; } @@ -132,8 +132,8 @@ public class EditorLineStatus extends JComponent { this.name = name; } - public void setSerialPort(String serialport) { - this.serialport = serialport; + public void setPort(String port) { + this.port = port; } public void setSerialNumber(String serialnumber) { From 4fffcd6e1a668f5065fd2762e493ce337d76207d Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 7 Dec 2018 12:37:09 +0100 Subject: [PATCH 23/28] Editor: use TargetBoard.getName() to get board name --- app/src/processing/app/Editor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 43e52da33..dc9f17327 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -93,6 +93,7 @@ import cc.arduino.view.StubMenuListener; import cc.arduino.view.findreplace.FindReplace; import jssc.SerialPortException; import processing.app.debug.RunnerException; +import processing.app.debug.TargetBoard; import processing.app.forms.PasswordAuthorizationDialog; import processing.app.helpers.DocumentTextChangeListener; import processing.app.helpers.Keys; @@ -2580,9 +2581,9 @@ public class Editor extends JFrame implements RunnerListener { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . protected void onBoardOrPortChange() { - Map boardPreferences = BaseNoGui.getBoardPreferences(); - if (boardPreferences != null) - lineStatus.setBoardName(boardPreferences.get("name")); + TargetBoard board = BaseNoGui.getTargetBoard(); + if (board != null) + lineStatus.setBoardName(board.getName()); else lineStatus.setBoardName("-"); lineStatus.setPort(PreferencesData.get("serial.port")); From 651dcd52711c52471166659edeac35000209cda4 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 7 Dec 2018 12:38:04 +0100 Subject: [PATCH 24/28] Removed unused field --- app/src/processing/app/EditorLineStatus.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java index 4163370d2..7635437da 100644 --- a/app/src/processing/app/EditorLineStatus.java +++ b/app/src/processing/app/EditorLineStatus.java @@ -52,7 +52,6 @@ public class EditorLineStatus extends JComponent { String text = ""; String name = ""; String port = ""; - String serialnumber = ""; public EditorLineStatus() { background = Theme.getColor("linestatus.bgcolor"); @@ -136,10 +135,6 @@ public class EditorLineStatus extends JComponent { this.port = port; } - public void setSerialNumber(String serialnumber) { - this.serialnumber = serialnumber; - } - public Dimension getPreferredSize() { return scale(new Dimension(300, height)); } From e1caaf1c456a3faebb07956254701ead83afe184 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 23 Jan 2019 15:46:41 +0100 Subject: [PATCH 25/28] Perform port selection after initializing packages Fix #8400 --- app/src/processing/app/Base.java | 2 ++ .../src/processing/app/helpers/CommandlineParser.java | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index e487231d5..00d64a53e 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -267,6 +267,8 @@ public class Base { splash.splashText(tr("Initializing packages...")); BaseNoGui.initPackages(); + parser.getUploadPort().ifPresent(BaseNoGui::selectSerialPort); + splash.splashText(tr("Preparing boards...")); if (!isCommandLine()) { diff --git a/arduino-core/src/processing/app/helpers/CommandlineParser.java b/arduino-core/src/processing/app/helpers/CommandlineParser.java index 83d34fed7..4c8b3a241 100644 --- a/arduino-core/src/processing/app/helpers/CommandlineParser.java +++ b/arduino-core/src/processing/app/helpers/CommandlineParser.java @@ -41,6 +41,7 @@ public class CommandlineParser { private String getPref; private String boardToInstall; private String libraryToInstall; + private Optional uploadPort = Optional.empty(); private final List filenames = new LinkedList<>(); public CommandlineParser(String[] args) { @@ -141,7 +142,7 @@ public class CommandlineParser { i++; if (i >= args.length) BaseNoGui.showError(null, tr("Argument required for --port"), 3); - BaseNoGui.selectSerialPort(args[i]); + uploadPort = Optional.of(args[i]); if (action == ACTION.GUI) action = ACTION.NOOP; continue; @@ -356,4 +357,8 @@ public class CommandlineParser { public boolean isPreserveTempFiles() { return preserveTempFiles; } + + public Optional getUploadPort() { + return uploadPort; + } } From feb863dfc98b27dda0d31d2f6ade72fe6006cb90 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 13 Dec 2018 18:09:36 +0100 Subject: [PATCH 26/28] PluggableDiscovery: allow patterns to contain runtime variables --- arduino-core/src/cc/arduino/packages/DiscoveryManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java index 47f502396..b344009db 100644 --- a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java +++ b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java @@ -39,6 +39,7 @@ import java.util.Map; import cc.arduino.packages.discoverers.PluggableDiscovery; import cc.arduino.packages.discoverers.serial.SerialDiscovery; import cc.arduino.packages.discoverers.NetworkDiscovery; +import processing.app.PreferencesData; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; import processing.app.helpers.PreferencesMap; @@ -75,6 +76,7 @@ public class DiscoveryManager { try { System.out.println("found discovery: " + discoveryName + " -> " + pattern); System.out.println("with preferencess -> " + discoveryPrefs); + pattern = StringReplacer.replaceFromMapping(pattern, PreferencesData.getMap()); String[] cmd = StringReplacer.formatAndSplit(pattern, discoveryPrefs); discoverers.add(new PluggableDiscovery(discoveryName, cmd)); } catch (Exception e) { From be1a8403f00f3aa200caab2cc194f20a5e4d0be3 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 7 Mar 2019 14:09:55 +0100 Subject: [PATCH 27/28] Add TargetBoard.getFQBN helper --- arduino-core/src/processing/app/debug/LegacyTargetBoard.java | 4 ++++ arduino-core/src/processing/app/debug/TargetBoard.java | 2 ++ 2 files changed, 6 insertions(+) diff --git a/arduino-core/src/processing/app/debug/LegacyTargetBoard.java b/arduino-core/src/processing/app/debug/LegacyTargetBoard.java index 16770a635..09e7ac508 100644 --- a/arduino-core/src/processing/app/debug/LegacyTargetBoard.java +++ b/arduino-core/src/processing/app/debug/LegacyTargetBoard.java @@ -100,4 +100,8 @@ public class LegacyTargetBoard implements TargetBoard { return containerPlatform; } + @Override + public String getFQBN() { + return getContainerPlatform().getContainerPackage().getId() + ":" + getContainerPlatform().getId() + ":" + getId(); + } } diff --git a/arduino-core/src/processing/app/debug/TargetBoard.java b/arduino-core/src/processing/app/debug/TargetBoard.java index 5dae86906..d635bbf1d 100644 --- a/arduino-core/src/processing/app/debug/TargetBoard.java +++ b/arduino-core/src/processing/app/debug/TargetBoard.java @@ -92,4 +92,6 @@ public interface TargetBoard { public TargetPlatform getContainerPlatform(); + public String getFQBN(); + } From d4bbf71b307bba3c7d17c4afec02afc6f47b36c0 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 7 Mar 2019 14:10:42 +0100 Subject: [PATCH 28/28] Match wildcard property "." with board fqbn/name --- arduino-core/src/cc/arduino/packages/BoardPort.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arduino-core/src/cc/arduino/packages/BoardPort.java b/arduino-core/src/cc/arduino/packages/BoardPort.java index 1f5181b89..2052339f1 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -144,6 +144,16 @@ public class BoardPort { PreferencesMap identificationProps = getIdentificationPrefs(); PreferencesMap boardProps = board.getPreferences(); + String wildMatcher = identificationProps.get("."); + if (wildMatcher != null) { + if (wildMatcher.equals(board.getId())) { + return true; + } + if (wildMatcher.equals(board.getFQBN())) { + return true; + } + } + // Identification properties are defined in boards.txt with a ".N" suffix // for example: //