From 690186201c9e960a91c7df0a9563270a339d1351 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 28 Sep 2018 18:01:37 -0700 Subject: [PATCH 1/3] 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 0e85ffe135d..bcab853842d 100644 --- a/arduino-core/src/cc/arduino/packages/BoardPort.java +++ b/arduino-core/src/cc/arduino/packages/BoardPort.java @@ -47,6 +47,18 @@ public 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 acb22b5d644ca44eca5e3a540c88d7fd68de8cfe Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 28 Sep 2018 18:04:35 -0700 Subject: [PATCH 2/3] 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 8bd435087f3..729b060e637 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 73b99ee91b9077f8b5520539055e572a10ec7f01 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Sat, 29 Sep 2018 00:07:37 -0700 Subject: [PATCH 3/3] 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 729b060e637..d4967c25791 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 PluggableDiscovery(String discoveryName, String[] cmd) { 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 void run() { 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 @@ private synchronized void update(BoardPort port) { // 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 synchronized List listDiscoveredBoards() { // 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; }