Skip to content

update Sketch menu, add Save hex option #2567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 93 additions & 26 deletions app/src/processing/app/Editor.java
Original file line number Diff line number Diff line change
@@ -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() {
10 changes: 5 additions & 5 deletions app/src/processing/app/Sketch.java
Original file line number Diff line number Diff line change
@@ -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;

4 changes: 2 additions & 2 deletions arduino-core/src/processing/app/BaseNoGui.java
Original file line number Diff line number Diff line change
@@ -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) {
58 changes: 49 additions & 9 deletions arduino-core/src/processing/app/debug/Compiler.java
Original file line number Diff line number Diff line change
@@ -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<File> 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<File>();

@@ -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: <buildPath>/<library>/
// Doesn't really use configPreferences
progressListener.progress(40);
progressListener.progress(30);
compileLibraries(includeFolders);

// 3. compile the core, outputting .o files to <buildPath> 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.output.tmp_file");
tmp_file = StringReplacer.replaceFromMapping(tmp_file, dict);
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);
File saveFile = new File(sketch.getFolder().getAbsolutePath() + "/" + save_file);

FileReader in = new FileReader(hexFile);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileUtils.copyFile may be used here.

FileWriter out = new FileWriter(saveFile);

int c;
while ((c = in.read()) != -1)
out.write(c);

in.close();
out.close();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May you add a message for verbose compile? Something like:

Copying output file xxxxxx.hex to /xxx/yyy/zzz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for AVR we would like to save the .eep ??

Arnav Gupta (championswimmer)
LinkedIn http://in.linkedin.com/in/arnavgupta/ | Web
http://championswimmer.in | Blog http://blog.championswimmer.in |
Twitter http://twitter.com/championswimmer | Facebook
http://facebook.com/championswimmer | Github
http://github.com/championswimmer

On 18 February 2015 at 16:08, Cristian Maglie [email protected]
wrote:

In arduino-core/src/processing/app/debug/Compiler.java
#2567 (comment):

  •  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);
    
  •  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();
    

May you add a message for verbose compile? Something like:

Copying output file xxxxxx.hex to /xxx/yyy/zzz

Reply to this email directly or view it on GitHub
https://github.com/arduino/Arduino/pull/2567/files#r24892263.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, maybe we would like to list the files as a comma separated list?

} catch (Exception e) {
throw new RunnerException(e);
}
}


private static String prepareIncludes(List<File> includeFolders) {
String res = "";
4 changes: 4 additions & 0 deletions hardware/arduino/avr/platform.txt
Original file line number Diff line number Diff line change
@@ -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.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"
recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).*
4 changes: 4 additions & 0 deletions hardware/arduino/sam/platform.txt
Original file line number Diff line number Diff line change
@@ -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.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"
recipe.size.regex=\.text\s+([0-9]+).*