diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index c149583a4..d346de61d 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -28,6 +28,7 @@ import java.io.*; import java.util.*; import java.util.List; +import javax.jmdns.ServiceEvent; import javax.swing.*; import processing.app.debug.TargetBoard; @@ -42,6 +43,8 @@ import processing.app.javax.swing.filechooser.FileNameExtensionFilter; import processing.app.packages.Library; import processing.app.packages.LibraryList; import processing.app.tools.ZipDeflater; +import processing.app.zeroconf.BoardListener; +import processing.app.zeroconf.Discovery; import processing.core.*; import static processing.app.I18n._; @@ -113,6 +116,7 @@ public class Base { // int editorCount; List editors = Collections.synchronizedList(new ArrayList()); Editor activeEditor; + final Map> boardsViaNetwork; static File portableFolder = null; static final String portableSketchbookFolder = "sketchbook"; @@ -253,6 +257,8 @@ public class Base { public Base(String[] args) throws Exception { platform.init(this); + this.boardsViaNetwork = new HashMap>(); + // Get the sketchbook path, and make sure it's set properly String sketchbookPath = Preferences.get("sketchbook.path"); @@ -353,21 +359,21 @@ public class Base { System.out.println(_("Can't open source sketch!")); System.exit(2); } - + // Set verbosity for command line build Preferences.set("build.verbose", "" + doVerbose); Preferences.set("upload.verbose", "" + doVerbose); Editor editor = editors.get(0); - + // Wait until editor is initialized while (!editor.status.isInitialized()) Thread.sleep(10); - + // Do board selection if requested if (selectBoard != null) selectBoard(selectBoard, editor); - + if (doUpload) { // Build and upload if (selectPort != null) @@ -377,12 +383,12 @@ public class Base { // Build only editor.runHandler.run(); } - + // Error during build or upload int res = editor.status.mode; if (res == EditorStatus.ERR) System.exit(1); - + // No errors exit gracefully System.exit(0); } @@ -400,6 +406,21 @@ public class Base { if (Preferences.getBoolean("update.check")) { new UpdateCheck(this); } + + new Discovery(new BoardListener() { + @Override + public void boardOffline(ServiceEvent serviceEvent) { + Base.this.boardsViaNetwork.remove(serviceEvent.getName()); + } + + @Override + public void boardOnline(ServiceEvent serviceEvent) { + Map board = new HashMap(); + board.put("addresses", serviceEvent.getInfo().getInet4Addresses()); + board.put("type", serviceEvent.getType()); + Base.this.boardsViaNetwork.put(serviceEvent.getName(), board); + } + }); } @@ -1180,7 +1201,7 @@ public class Base { TargetPlatform targetPlatform = getTargetPlatform(); if (targetPlatform == null) return; - + // Calculate paths for libraries and examples examplesFolder = getContentFile("examples"); toolsFolder = getContentFile("tools"); @@ -1201,7 +1222,7 @@ public class Base { } String currentArch = Base.getTargetPlatform().getId(); libraries = libraries.filterByArchitecture(currentArch); - + // Populate importToLibraryTable importToLibraryTable = new HashMap(); for (Library lib : libraries) { @@ -1491,7 +1512,7 @@ public class Base { final boolean replaceExisting) throws IOException { if (folder == null) return false; - + // skip .DS_Store files, etc (this shouldn't actually be necessary) if (!folder.isDirectory()) return false; @@ -1613,7 +1634,7 @@ public class Base { } }; action.putValue("library", lib); - + // Add new element at the bottom JMenuItem item = new JMenuItem(action); item.putClientProperty("library", lib); diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index c069b7c8a..0cc25863c 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -100,7 +100,7 @@ public class Editor extends JFrame implements RunnerListener { static JMenu serialMenu; static SerialMonitor serialMonitor; - + EditorHeader header; EditorStatus status; EditorConsole console; @@ -116,7 +116,7 @@ public class Editor extends JFrame implements RunnerListener { EditorLineStatus lineStatus; //JEditorPane editorPane; - + JEditTextArea textarea; EditorListener listener; @@ -207,7 +207,7 @@ public class Editor extends JFrame implements RunnerListener { serialMonitor = new SerialMonitor(Preferences.get("serial.port")); serialMonitor.setIconImage(getIconImage()); } - + buildMenuBar(); // For rev 0120, placing things inside a JPanel @@ -675,7 +675,7 @@ public class Editor extends JFrame implements RunnerListener { JMenuItem item; addInternalTools(menu); - + item = newJMenuItemShift(_("Serial Monitor"), 'M'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -683,18 +683,18 @@ public class Editor extends JFrame implements RunnerListener { } }); menu.add(item); - + addTools(menu, Base.getToolsFolder()); File sketchbookTools = new File(Base.getSketchbookFolder(), "tools"); addTools(menu, sketchbookTools); menu.addSeparator(); - + numTools = menu.getItemCount(); - + // XXX: DAM: these should probably be implemented using the Tools plugin // API, if possible (i.e. if it supports custom actions, etc.) - + if (boardsMenus == null) { boardsMenus = new LinkedList(); @@ -707,13 +707,13 @@ public class Editor extends JFrame implements RunnerListener { importMenu.removeAll(); base.rebuildImportMenu(importMenu, this); } - + if (serialMenu == null) serialMenu = new JMenu(_("Serial Port")); populateSerialMenu(); menu.add(serialMenu); menu.addSeparator(); - + JMenu programmerMenu = new JMenu(_("Programmer")); base.rebuildProgrammerMenu(programmerMenu); menu.add(programmerMenu); @@ -725,7 +725,7 @@ public class Editor extends JFrame implements RunnerListener { } }); menu.add(item); - + menu.addMenuListener(new MenuListener() { public void menuCanceled(MenuEvent e) {} public void menuDeselected(MenuEvent e) {} @@ -742,7 +742,7 @@ public class Editor extends JFrame implements RunnerListener { protected void addTools(JMenu menu, File sourceFolder) { if (sourceFolder == null) return; - + Map toolItems = new HashMap(); File[] folders = sourceFolder.listFiles(new FileFilter() { @@ -975,14 +975,7 @@ public class Editor extends JFrame implements RunnerListener { protected void populateSerialMenu() { - // getting list of ports - - JMenuItem rbMenuItem; - - //System.out.println("Clearing serial port menu."); - serialMenu.removeAll(); - boolean empty = true; try { @@ -991,8 +984,7 @@ public class Editor extends JFrame implements RunnerListener { { CommPortIdentifier commportidentifier = (CommPortIdentifier)enumeration.nextElement(); //System.out.println("Found communication port: " + commportidentifier); - if (commportidentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) - { + if (commportidentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) { //System.out.println("Adding port to serial port menu: " + commportidentifier); String curr_port = commportidentifier.getName(); @@ -1001,32 +993,26 @@ public class Editor extends JFrame implements RunnerListener { if (additionalDescription != null) { description += " (" + additionalDescription + ")"; } - rbMenuItem = new JCheckBoxMenuItem(description, curr_port.equals(Preferences.get("serial.port"))); + JCheckBoxMenuItem rbMenuItem = new JCheckBoxMenuItem(description, curr_port.equals(Preferences.get("serial.port"))); rbMenuItem.addActionListener(new SerialMenuListener(curr_port)); //serialGroup.add(rbMenuItem); serialMenu.add(rbMenuItem); - empty = false; } } - if (!empty) { - //System.out.println("enabling the serialMenu"); - serialMenu.setEnabled(true); - } - - } - - catch (Exception exception) - { + } catch (Exception exception) { System.out.println(_("error retrieving port list")); exception.printStackTrace(); } - - if (serialMenu.getItemCount() == 0) { - serialMenu.setEnabled(false); + + for (Map.Entry> entry : base.boardsViaNetwork.entrySet()) { + Inet4Address[] a = (Inet4Address[]) entry.getValue().get("addresses"); + String label = entry.getKey() + "@" + a[0].toString(); + JCheckBoxMenuItem rbMenuItem = new JCheckBoxMenuItem(label, label.equals(Preferences.get("serial.port"))); + rbMenuItem.addActionListener(new SerialMenuListener(label)); + serialMenu.add(rbMenuItem); } - //serialMenu.addSeparator(); - //serialMenu.add(item); + serialMenu.setEnabled(serialMenu.getMenuComponentCount() > 0); } @@ -1887,7 +1873,7 @@ public class Editor extends JFrame implements RunnerListener { int length = endIndex - current + startOffset; text = textarea.getDocument().getText(current - startOffset, length); - + } catch (BadLocationException bl) { bl.printStackTrace(); } finally { @@ -1897,7 +1883,7 @@ public class Editor extends JFrame implements RunnerListener { protected void handleFindReference() { String text = getCurrentKeyword(); - + String referenceFile = PdeKeywords.getReference(text); if (referenceFile == null) { statusNotice(I18n.format(_("No reference available for \"{0}\""), text)); @@ -2153,7 +2139,7 @@ public class Editor extends JFrame implements RunnerListener { File altPdeFile = new File(parent, pdeName); String inoName = parentName + ".ino"; File altInoFile = new File(parent, pdeName); - + if (pdeName.equals(fileName) || inoName.equals(fileName)) { // no beef with this guy @@ -2358,8 +2344,8 @@ public class Editor extends JFrame implements RunnerListener { return true; } - - + + public boolean serialPrompt() { int count = serialMenu.getItemCount(); Object[] names = new Object[count]; @@ -2417,9 +2403,9 @@ public class Editor extends JFrame implements RunnerListener { try { serialMonitor.closeSerialPort(); serialMonitor.setVisible(false); - + uploading = true; - + boolean success = sketch.exportApplet(false); if (success) { statusNotice(_("Done uploading.")); @@ -2453,9 +2439,9 @@ public class Editor extends JFrame implements RunnerListener { try { serialMonitor.closeSerialPort(); serialMonitor.setVisible(false); - + uploading = true; - + boolean success = sketch.exportApplet(true); if (success) { statusNotice(_("Done uploading.")); @@ -2519,7 +2505,7 @@ public class Editor extends JFrame implements RunnerListener { public void handleSerial() { if (uploading) return; - + try { serialMonitor.openSerialPort(); serialMonitor.setVisible(true); @@ -2697,7 +2683,7 @@ public class Editor extends JFrame implements RunnerListener { lineStatus.repaint(); } - + /** * Returns the edit popup menu. */ @@ -2722,10 +2708,10 @@ public class Editor extends JFrame implements RunnerListener { } }); add(openURLItem); - + openURLItemSeparator = new JSeparator(); add(openURLItemSeparator); - + cutItem = new JMenuItem(_("Cut")); cutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -2824,7 +2810,7 @@ public class Editor extends JFrame implements RunnerListener { openURLItem.setVisible(false); openURLItemSeparator.setVisible(false); } - + if (textarea.isSelectionActive()) { cutItem.setEnabled(true); copyItem.setEnabled(true); @@ -2835,10 +2821,10 @@ public class Editor extends JFrame implements RunnerListener { copyItem.setEnabled(false); discourseItem.setEnabled(false); } - + referenceFile = PdeKeywords.getReference(getCurrentKeyword()); referenceItem.setEnabled(referenceFile != null); - + super.show(component, x, y); } } diff --git a/app/src/processing/app/zeroconf/Discovery.java b/app/src/processing/app/zeroconf/Discovery.java index 423114740..ba95163d1 100644 --- a/app/src/processing/app/zeroconf/Discovery.java +++ b/app/src/processing/app/zeroconf/Discovery.java @@ -1,9 +1,12 @@ package processing.app.zeroconf; +import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter; + import javax.jmdns.JmDNS; import javax.jmdns.NetworkTopologyDiscovery; import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceListener; +import javax.jmdns.impl.DNSTaskStarter; import java.io.IOException; import java.net.InetAddress; @@ -11,6 +14,10 @@ public class Discovery implements ServiceListener { private final BoardListener listener; + static { + DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter()); + } + public Discovery(BoardListener listener) throws IOException { this.listener = listener; for (InetAddress addr : NetworkTopologyDiscovery.Factory.getInstance().getInetAddresses()) { @@ -21,7 +28,7 @@ public class Discovery implements ServiceListener { @Override public void serviceAdded(ServiceEvent serviceEvent) { - serviceEvent.getDNS().requestServiceInfo(serviceEvent.getInfo().getServer(), serviceEvent.getName(), true); + serviceEvent.getDNS().requestServiceInfo(serviceEvent.getInfo().getServer(), serviceEvent.getName()); } @Override @@ -33,4 +40,5 @@ public class Discovery implements ServiceListener { public void serviceResolved(ServiceEvent serviceEvent) { listener.boardOnline(serviceEvent); } + } diff --git a/app/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java b/app/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java new file mode 100644 index 000000000..3243ae48d --- /dev/null +++ b/app/src/processing/app/zeroconf/jmdns/ArduinoDNSTaskStarter.java @@ -0,0 +1,80 @@ +package processing.app.zeroconf.jmdns; + +import javax.jmdns.impl.DNSIncoming; +import javax.jmdns.impl.DNSTaskStarter; +import javax.jmdns.impl.JmDNSImpl; +import javax.jmdns.impl.ServiceInfoImpl; +import javax.jmdns.impl.tasks.RecordReaper; +import java.util.Timer; + +public class ArduinoDNSTaskStarter implements DNSTaskStarter.Factory.ClassDelegate { + + @Override + public DNSTaskStarter newDNSTaskStarter(final JmDNSImpl jmDNSImpl) { + final DNSTaskStarter.DNSTaskStarterImpl delegate = new DNSTaskStarter.DNSTaskStarterImpl(jmDNSImpl); + final DNSTaskStarter.DNSTaskStarterImpl.StarterTimer timer = new DNSTaskStarter.DNSTaskStarterImpl.StarterTimer("JmDNS(" + jmDNSImpl.getName() + ").Timer", true); + + return new DNSTaskStarter() { + + public void purgeTimer() { + delegate.purgeTimer(); + } + + public void purgeStateTimer() { + delegate.purgeStateTimer(); + } + + public void cancelTimer() { + delegate.cancelTimer(); + timer.cancel(); + } + + public void cancelStateTimer() { + delegate.cancelStateTimer(); + } + + public void startProber() { + delegate.startProber(); + } + + public void startAnnouncer() { + delegate.startAnnouncer(); + } + + public void startRenewer() { + delegate.startRenewer(); + } + + public void startCanceler() { + delegate.startCanceler(); + } + + public void startReaper() { + new RecordReaper(jmDNSImpl) { + @Override + public void start(Timer timer) { + if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) { + timer.schedule(this, 0, 500); + } + } + }.start(timer); + } + + public void startServiceInfoResolver(ServiceInfoImpl info) { + delegate.startServiceInfoResolver(info); + } + + public void startTypeResolver() { + delegate.startTypeResolver(); + } + + public void startServiceResolver(String type) { + delegate.startServiceResolver(type); + } + + public void startResponder(DNSIncoming in, int port) { + delegate.startResponder(in, port); + } + }; + } +}