From ded51276382c19513b6fae879c924b2f9d38d569 Mon Sep 17 00:00:00 2001 From: Arnav Gupta Date: Fri, 23 Jan 2015 08:30:46 +0530 Subject: [PATCH 1/3] update Sketch menu, add Save hex option * Moving Upload options from "File" menu to "Sketch" menu as those are sketch actions more than file actions. Signed-off-by: Arnav Gupta --- app/src/processing/app/Editor.java | 119 ++++++++++++++---- app/src/processing/app/Sketch.java | 10 +- .../src/processing/app/BaseNoGui.java | 4 +- .../src/processing/app/debug/Compiler.java | 58 +++++++-- hardware/arduino/avr/platform.txt | 4 + hardware/arduino/sam/platform.txt | 4 + 6 files changed, 157 insertions(+), 42 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 6842a5bbd81..09c1e033163 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -153,6 +153,8 @@ public class Editor extends JFrame implements RunnerListener { Runnable runHandler; Runnable presentHandler; + Runnable runAndSaveHandler; + Runnable presentAndSaveHandler; Runnable stopHandler; Runnable exportHandler; Runnable exportAppHandler; @@ -557,22 +559,6 @@ public void actionPerformed(ActionEvent e) { }); fileMenu.add(saveAsMenuItem); - item = newJMenuItem(_("Upload"), 'U'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleExport(false); - } - }); - fileMenu.add(item); - - item = newJMenuItemShift(_("Upload Using Programmer"), 'U'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleExport(true); - } - }); - fileMenu.add(item); - fileMenu.addSeparator(); item = newJMenuItemShift(_("Page Setup"), 'P'); @@ -620,6 +606,7 @@ public void actionPerformed(ActionEvent e) { protected JMenu buildSketchMenu() { JMenuItem item; sketchMenu = new JMenu(_("Sketch")); + item = newJMenuItem(_("Verify / Compile"), 'R'); item.addActionListener(new ActionListener() { @@ -628,14 +615,31 @@ public void actionPerformed(ActionEvent e) { } }); sketchMenu.add(item); + + item = newJMenuItem(_("Upload"), 'U'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleExport(false); + } + }); + sketchMenu.add(item); -// item = newJMenuItemShift("Verify / Compile (verbose)", 'R'); -// item.addActionListener(new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// handleRun(true); -// } -// }); -// sketchMenu.add(item); + item = newJMenuItemShift(_("Upload Using Programmer"), 'U'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleExport(true); + } + }); + sketchMenu.add(item); + + + item = newJMenuItemAlt("Export compiled Binary", 'S'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRunAndSave(true); + } + }); + sketchMenu.add(item); // item = new JMenuItem("Stop"); // item.addActionListener(new ActionListener() { @@ -1414,11 +1418,17 @@ protected void updateRedoState() { // abstract from the editor in this fashion. - public void setHandlers(Runnable runHandler, Runnable presentHandler, + public void setHandlers(Runnable runHandler, + Runnable presentHandler, + Runnable runAndSaveHandler, + Runnable presentAndSaveHandler, Runnable stopHandler, - Runnable exportHandler, Runnable exportAppHandler) { + Runnable exportHandler, + Runnable exportAppHandler) { this.runHandler = runHandler; this.presentHandler = presentHandler; + this.runAndSaveHandler = runAndSaveHandler; + this.presentAndSaveHandler = presentAndSaveHandler; this.stopHandler = stopHandler; this.exportHandler = exportHandler; this.exportAppHandler = exportAppHandler; @@ -1428,6 +1438,8 @@ public void setHandlers(Runnable runHandler, Runnable presentHandler, public void resetHandlers() { runHandler = new BuildHandler(); presentHandler = new BuildHandler(true); + runAndSaveHandler = new BuildAndSaveHandler(); + presentAndSaveHandler = new BuildAndSaveHandler(true); stopHandler = new DefaultStopHandler(); exportHandler = new DefaultExportHandler(); exportAppHandler = new DefaultExportAppHandler(); @@ -1916,6 +1928,29 @@ public void handleRun(final boolean verbose) { // placed on the event thread and causes a hang--bad idea all around. new Thread(verbose ? presentHandler : runHandler).start(); } + + /** + * Implements Sketch → Run and Save. + * @param verbose Set true to run with verbose output. + */ + public void handleRunAndSave(final boolean verbose) { + internalCloseRunner(); + running = true; + toolbar.activate(EditorToolbar.RUN); + status.progress(_("Compiling sketch...")); + + // do this to advance/clear the terminal window / dos prompt / etc + for (int i = 0; i < 10; i++) System.out.println(); + + // clear the console on each run, unless the user doesn't want to + if (Preferences.getBoolean("console.auto_clear")) { + console.clear(); + } + + // Cannot use invokeLater() here, otherwise it gets + // placed on the event thread and causes a hang--bad idea all around. + new Thread(verbose ? presentAndSaveHandler : runAndSaveHandler).start(); + } class BuildHandler implements Runnable { @@ -1933,7 +1968,7 @@ public BuildHandler(boolean verbose) { public void run() { try { sketch.prepare(); - sketch.build(verbose); + sketch.build(verbose, false); statusNotice(_("Done compiling.")); } catch (PreferencesMapException e) { statusError(I18n.format( @@ -1948,6 +1983,38 @@ public void run() { toolbar.deactivate(EditorToolbar.RUN); } } + + class BuildAndSaveHandler implements Runnable { + + private final boolean verbose; + + public BuildAndSaveHandler() { + this(false); + } + + public BuildAndSaveHandler(boolean verbose) { + this.verbose = verbose; + } + + @Override + public void run() { + try { + sketch.prepare(); + sketch.build(verbose, true); + statusNotice(_("Done compiling.")); + } catch (PreferencesMapException e) { + statusError(I18n.format( + _("Error while compiling: missing '{0}' configuration parameter"), + e.getMessage())); + } catch (Exception e) { + status.unprogress(); + statusError(e); + } + + status.unprogress(); + toolbar.deactivate(EditorToolbar.RUN); + } + } class DefaultStopHandler implements Runnable { public void run() { diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 8a32717f712..6c3fc7454db 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -1130,8 +1130,8 @@ public void prepare() throws IOException { * @return null if compilation failed, main class name if not * @throws RunnerException */ - public String build(boolean verbose) throws RunnerException, PreferencesMapException { - return build(tempBuildFolder.getAbsolutePath(), verbose); + public String build(boolean verbose, boolean save) throws RunnerException, PreferencesMapException { + return build(tempBuildFolder.getAbsolutePath(), verbose, save); } /** @@ -1143,7 +1143,7 @@ public String build(boolean verbose) throws RunnerException, PreferencesMapExcep * * @return null if compilation failed, main class name if not */ - public String build(String buildPath, boolean verbose) throws RunnerException, PreferencesMapException { + public String build(String buildPath, boolean verbose, boolean save) throws RunnerException, PreferencesMapException { // run the preprocessor editor.status.progressUpdate(20); @@ -1156,7 +1156,7 @@ public void progress(int percent) { } }; - return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose); + return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose, save); } protected boolean exportApplet(boolean usingProgrammer) throws Exception { @@ -1174,7 +1174,7 @@ public boolean exportApplet(String appletPath, boolean usingProgrammer) // build the sketch editor.status.progressNotice(_("Compiling sketch...")); - String foundName = build(appletPath, false); + String foundName = build(appletPath, false, false); // (already reported) error during export, exit this function if (foundName == null) return false; diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index 100db6a66ab..0a08db5363f 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -499,7 +499,7 @@ static public void init(String[] args) { // - calls Sketch.build(verbose=false) that calls Sketch.ensureExistence(), set progressListener and calls Compiler.build() // - calls Sketch.upload() (see later...) if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null); - String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild()); + String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false); if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null); showMessage(_("Done compiling"), _("Done compiling")); @@ -544,7 +544,7 @@ static public void init(String[] args) { // if (!data.getFolder().exists()) showError(...); // String ... = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, verbose); if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null); - String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild()); + String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false); if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null); showMessage(_("Done compiling"), _("Done compiling")); } catch (Exception e) { diff --git a/arduino-core/src/processing/app/debug/Compiler.java b/arduino-core/src/processing/app/debug/Compiler.java index 652d7c77fcf..7fff1111ec5 100644 --- a/arduino-core/src/processing/app/debug/Compiler.java +++ b/arduino-core/src/processing/app/debug/Compiler.java @@ -30,6 +30,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -67,6 +68,7 @@ public class Compiler implements MessageConsumer { private SketchData sketch; private PreferencesMap prefs; private boolean verbose; + private boolean saveHex; private List objectFiles; @@ -83,7 +85,7 @@ public interface ProgressListener { private ProgressListener progressListener; - static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose) throws RunnerException, PreferencesMapException { + static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose, boolean save) throws RunnerException, PreferencesMapException { if (SketchData.checkSketchFile(data.getPrimaryFile()) == null) BaseNoGui.showError(_("Bad file selected"), _("Bad sketch primary file or bad sketch directory structure"), null); @@ -112,7 +114,7 @@ static public String build(SketchData data, String buildPath, File tempBuildFold // compile the program. errors will happen as a RunnerException // that will bubble up to whomever called build(). - if (compiler.compile(verbose)) { + if (compiler.compile(verbose, save)) { compiler.size(compiler.getBuildPreferences()); return primaryClassName; } @@ -340,10 +342,11 @@ protected void size(PreferencesMap prefs) throws RunnerException { * @return true if successful. * @throws RunnerException Only if there's a problem. Only then. */ - public boolean compile(boolean _verbose) throws RunnerException, PreferencesMapException { + public boolean compile(boolean _verbose, boolean _save) throws RunnerException, PreferencesMapException { preprocess(prefs.get("build.path")); verbose = _verbose || PreferencesData.getBoolean("build.verbose"); + saveHex = _save; sketchIsCompiled = false; objectFiles = new ArrayList(); @@ -381,31 +384,37 @@ public boolean compile(boolean _verbose) throws RunnerException, PreferencesMapE } // 1. compile the sketch (already in the buildPath) - progressListener.progress(30); + progressListener.progress(20); compileSketch(includeFolders); sketchIsCompiled = true; // 2. compile the libraries, outputting .o files to: // // Doesn't really use configPreferences - progressListener.progress(40); + progressListener.progress(30); compileLibraries(includeFolders); // 3. compile the core, outputting .o files to and then // collecting them into the core.a library file. - progressListener.progress(50); + progressListener.progress(40); compileCore(); // 4. link it all together into the .elf file - progressListener.progress(60); + progressListener.progress(50); compileLink(); // 5. extract EEPROM data (from EEMEM directive) to .eep file. - progressListener.progress(70); + progressListener.progress(60); runRecipe("recipe.objcopy.eep.pattern"); // 6. build the .hex file - progressListener.progress(80); + progressListener.progress(70); runRecipe("recipe.objcopy.hex.pattern"); + + // 7. save the hex file + if (saveHex) { + progressListener.progress(80); + saveHex(); + } progressListener.progress(90); return true; @@ -1042,6 +1051,37 @@ void runRecipe(String recipe) throws RunnerException, PreferencesMapException { } execAsynchronously(cmdArray); } + + //7. Save the .hex file + void saveHex() throws RunnerException { + PreferencesMap dict = new PreferencesMap(prefs); + dict.put("ide_version", "" + BaseNoGui.REVISION); + + String[] cmdArray; + try { + String tmp_file = prefs.getOrExcept("recipe.hex.tmp_file"); + tmp_file = StringReplacer.replaceFromMapping(tmp_file, dict); + String save_file = prefs.getOrExcept("recipe.hex.save_file"); + save_file = StringReplacer.replaceFromMapping(save_file, dict); + + File hexFile = new File(prefs.get("build.path") + "/" + tmp_file); + File saveFile = new File(sketch.getFolder().getAbsolutePath() + "/" + save_file); + + FileReader in = new FileReader(hexFile); + FileWriter out = new FileWriter(saveFile); + + int c; + while ((c = in.read()) != -1) + out.write(c); + + in.close(); + out.close(); + + } catch (Exception e) { + throw new RunnerException(e); + } + } + private static String prepareIncludes(List includeFolders) { String res = ""; diff --git a/hardware/arduino/avr/platform.txt b/hardware/arduino/avr/platform.txt index 834774614ef..b00b34d9c43 100644 --- a/hardware/arduino/avr/platform.txt +++ b/hardware/arduino/avr/platform.txt @@ -67,6 +67,10 @@ recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.obj ## Create hex recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" +## Save hex +recipe.hex.tmp_file={build.project_name}.hex +recipe.hex.save_file={build.project_name}.{build.variant}.hex + ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).* diff --git a/hardware/arduino/sam/platform.txt b/hardware/arduino/sam/platform.txt index 85522faf4d0..f14c9acbb23 100644 --- a/hardware/arduino/sam/platform.txt +++ b/hardware/arduino/sam/platform.txt @@ -71,6 +71,10 @@ recipe.objcopy.eep.pattern= ## Create hex recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" +## Save hex +recipe.hex.tmp_file={build.project_name}.bin +recipe.hex.save_file={build.project_name}.{build.variant}.bin + ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" recipe.size.regex=\.text\s+([0-9]+).* From fa992e7ea18d7eb078a43123079809cff2a8037b Mon Sep 17 00:00:00 2001 From: Arnav Gupta Date: Thu, 5 Feb 2015 04:00:47 +0530 Subject: [PATCH 2/3] Make the export option string translatable --- app/src/processing/app/Editor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 09c1e033163..3b576e21e4d 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -4,7 +4,7 @@ Part of the Processing project - http://processing.org Copyright (c) 2004-09 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology + Copyright (c) 2001-04 Massachusetts Institute of Technol("Expoogy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -633,7 +633,7 @@ public void actionPerformed(ActionEvent e) { sketchMenu.add(item); - item = newJMenuItemAlt("Export compiled Binary", 'S'); + item = newJMenuItemAlt(_("Export compiled Binary"), 'S'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleRunAndSave(true); From c28ea8c73cdaf7b415f8aa2ee334a1c4508c8ad4 Mon Sep 17 00:00:00 2001 From: Arnav Gupta Date: Tue, 10 Feb 2015 03:54:48 +0530 Subject: [PATCH 3/3] saveHex: rename recipe.hex -> recipe.output Signed-off-by: Arnav Gupta --- app/src/processing/app/Editor.java | 2 +- arduino-core/src/processing/app/debug/Compiler.java | 4 ++-- hardware/arduino/avr/platform.txt | 4 ++-- hardware/arduino/sam/platform.txt | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3b576e21e4d..fdd35c262ae 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -4,7 +4,7 @@ Part of the Processing project - http://processing.org Copyright (c) 2004-09 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technol("Expoogy + Copyright (c) 2001-04 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 diff --git a/arduino-core/src/processing/app/debug/Compiler.java b/arduino-core/src/processing/app/debug/Compiler.java index 7fff1111ec5..5915e53b5d5 100644 --- a/arduino-core/src/processing/app/debug/Compiler.java +++ b/arduino-core/src/processing/app/debug/Compiler.java @@ -1059,9 +1059,9 @@ void saveHex() throws RunnerException { String[] cmdArray; try { - String tmp_file = prefs.getOrExcept("recipe.hex.tmp_file"); + String tmp_file = prefs.getOrExcept("recipe.output.tmp_file"); tmp_file = StringReplacer.replaceFromMapping(tmp_file, dict); - String save_file = prefs.getOrExcept("recipe.hex.save_file"); + String save_file = prefs.getOrExcept("recipe.output.save_file"); save_file = StringReplacer.replaceFromMapping(save_file, dict); File hexFile = new File(prefs.get("build.path") + "/" + tmp_file); diff --git a/hardware/arduino/avr/platform.txt b/hardware/arduino/avr/platform.txt index b00b34d9c43..797eb15f535 100644 --- a/hardware/arduino/avr/platform.txt +++ b/hardware/arduino/avr/platform.txt @@ -68,8 +68,8 @@ recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.obj recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" ## Save hex -recipe.hex.tmp_file={build.project_name}.hex -recipe.hex.save_file={build.project_name}.{build.variant}.hex +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" diff --git a/hardware/arduino/sam/platform.txt b/hardware/arduino/sam/platform.txt index f14c9acbb23..1095075f14d 100644 --- a/hardware/arduino/sam/platform.txt +++ b/hardware/arduino/sam/platform.txt @@ -72,8 +72,8 @@ recipe.objcopy.eep.pattern= recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" ## Save hex -recipe.hex.tmp_file={build.project_name}.bin -recipe.hex.save_file={build.project_name}.{build.variant}.bin +recipe.output.tmp_file={build.project_name}.bin +recipe.output.save_file={build.project_name}.{build.variant}.bin ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"