Added source to maple_loader.jar

This commit is contained in:
Roger Clark 2015-07-20 06:38:38 +10:00
parent 9c951d40d6
commit ce70ae4fce
37 changed files with 3287 additions and 0 deletions

View File

@ -0,0 +1,5 @@
These files build the maple_loader.jar file used on Windows to reset the Sketch via USB Serial, so that the bootloader will run in dfu upload mode, ready for a new sketch to be uploaded
The files were written by @bobC (github) and have been slightly modified by me (Roger Clark), so that dfu-util no longer attempts to reset the board after upload.
This change to dfu-util's reset command line argument, was required because dfu-util was showing errors on some Windows systems, because the bootloader had reset its self after upload,
before dfu-util had chance to tell it to reset.

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="maple_loader" default="default" basedir=".">
<description>Builds, tests, and runs the project maple_loader.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="maple_loader-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@ -0,0 +1,4 @@
#Mon, 20 Jul 2015 11:21:26 +1000
C\:\\Users\\rclark\\Desktop\\maple-asp-master\\installer\\maple_loader=

32
tools/src/maple_loader/dist/README.TXT vendored Normal file
View File

@ -0,0 +1,32 @@
========================
BUILD OUTPUT DESCRIPTION
========================
When you build an Java application project that has a main class, the IDE
automatically copies all of the JAR
files on the projects classpath to your projects dist/lib folder. The IDE
also adds each of the JAR files to the Class-Path element in the application
JAR files manifest file (MANIFEST.MF).
To run the project from the command line, go to the dist folder and
type the following:
java -jar "maple_loader.jar"
To distribute this project, zip up the dist folder (including the lib folder)
and distribute the ZIP file.
Notes:
* If two JAR files on the project classpath have the same name, only the first
JAR file is copied to the lib folder.
* Only JAR files are copied to the lib folder.
If the classpath contains other types of files or folders, these files (folders)
are not copied.
* If a library on the projects classpath also has a Class-Path element
specified in the manifest,the content of the Class-Path element has to be on
the projects runtime path.
* To set a main class in a standard Java project, right-click the project node
in the Projects window and choose Properties. Then click Run and enter the
class name in the Main Class field. Alternatively, you can manually type the
class name in the manifest Main-Class element.

BIN
tools/src/maple_loader/dist/lib/jssc.jar vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
build.xml.data.CRC32=2e6a03ba
build.xml.script.CRC32=4676ee6b
build.xml.stylesheet.CRC32=8064a381@1.75.2.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=2e6a03ba
nbproject/build-impl.xml.script.CRC32=392b3f79
nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48

View File

@ -0,0 +1,6 @@
compile.on.save=true
do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
user.properties.file=C:\\Users\\rclark\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group>
<file>file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/CliMain.java</file>
<file>file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/DFUUploader.java</file>
</group>
</open-files>
</project-private>

View File

@ -0,0 +1,79 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=maple_loader
application.vendor=bob
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# Files in build.classes.dir which should be excluded from distribution jar
dist.archive.excludes=
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/maple_loader.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.jssc.jar=dist/lib/jssc.jar
file.reference.jssc.jar-1=jars/jssc.jar
includes=**
jar.compress=false
javac.classpath=\
${file.reference.jssc.jar}:\
${file.reference.jssc.jar-1}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.7
javac.target=1.7
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=CliTemplate.CliMain
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project.
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
# To set system properties for unit tests define test-sys-prop.name=value:
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>maple_loader</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@ -0,0 +1,60 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package CliTemplate;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import processing.app.Preferences;
//import processing.app.I18n;
import processing.app.helpers.ProcessUtils;
/**
*
* @author cousinr
*/
public class CliMain {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String comPort = args[0]; //
String altIf = args[1]; //
String usbID = args[2]; // "1EAF:0003";
String binFile = args[3]; // bin file
System.out.println("maple_loader v0.1");
Preferences.set ("serial.port",comPort);
Preferences.set ("serial.parity","N");
Preferences.setInteger ("serial.databits", 8);
Preferences.setInteger ("serial.debug_rate",9600);
Preferences.setInteger ("serial.stopbits",1);
Preferences.setInteger ("programDelay",1200);
Preferences.set ("upload.usbID", usbID);
Preferences.set ("upload.altID", altIf);
Preferences.setBoolean ("upload.auto_reset", true);
Preferences.setBoolean ("upload.verbose", false);
//
DFUUploader dfuUploader = new DFUUploader();
try {
//dfuUploader.uploadViaDFU(binFile);
dfuUploader.uploadViaDFU(binFile);
} catch (Exception e)
{
System.err.print (MessageFormat.format("an error occurred! {0}\n", e.getMessage()));
}
}
}

View File

@ -0,0 +1,345 @@
/*
DFUUploader - uploader implementation using DFU
Copyright (c) 2010
Andrew Meyer
This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package CliTemplate;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import processing.app.Preferences;
import processing.app.Serial;
import processing.app.debug.MessageConsumer;
import processing.app.debug.MessageSiphon;
import processing.app.debug.RunnerException;
/**
*
* @author bob
*/
public class DFUUploader implements MessageConsumer {
boolean firstErrorFound;
boolean secondErrorFound;
// part of the PdeMessageConsumer interface
boolean notFoundError;
boolean verbose;
RunnerException exception;
static final String SUPER_BADNESS =
"Compiler error!";
public boolean uploadUsingPreferences(String binPath, boolean verbose)
throws RunnerException {
this.verbose = verbose;
return uploadViaDFU(binPath);
}
// works with old and new versions of dfu-util
private boolean found_device (String dfuData, String usbID)
{
return dfuData.contains(("Found DFU: [0x"+usbID.substring(0,4)).toUpperCase()) ||
dfuData.contains(("Found DFU: ["+usbID.substring(0,4)).toUpperCase());
}
public boolean uploadViaDFU (String binPath)
throws RunnerException {
this.verbose = Preferences.getBoolean ("upload.verbose");
/* todo, check for size overruns! */
String fileType="bin";
if (fileType.equals("bin")) {
String usbID = Preferences.get("upload.usbID");
if (usbID == null) {
/* fall back on default */
/* this isnt great because is default Avrdude or dfu-util? */
usbID = Preferences.get("upload.usbID");
}
/* if auto-reset, then emit the reset pulse on dtr/rts */
if (Preferences.get("upload.auto_reset") != null) {
if (Preferences.get("upload.auto_reset").toLowerCase().equals("true")) {
System.out.println("Resetting to bootloader via DTR pulse");
emitResetPulse();
}
} else {
System.out.println("Resetting to bootloader via DTR pulse");
emitResetPulse();
}
String dfuList = new String();
List commandCheck = new ArrayList();
commandCheck.add("dfu-util");
commandCheck.add("-l");
long startChecking = System.currentTimeMillis();
System.out.println("Searching for DFU device [" + usbID + "]...");
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
dfuList = executeCheckCommand(commandCheck);
//System.out.println(dfuList);
}
while ( !found_device (dfuList.toUpperCase(), usbID) && (System.currentTimeMillis() - startChecking < 7000));
if ( !found_device (dfuList.toUpperCase(), usbID) )
{
System.out.println(dfuList);
System.err.println("Couldn't find the DFU device: [" + usbID + "]");
return false;
}
System.out.println("Found it!");
/* todo, add handle to let user choose altIf at upload time! */
String altIf = Preferences.get("upload.altID");
List commandDownloader = new ArrayList();
commandDownloader.add("dfu-util");
commandDownloader.add("-a "+altIf);
commandDownloader.add("-R");
commandDownloader.add("-d "+usbID);
commandDownloader.add("-D"+ binPath); //"./thisbin.bin");
return executeUploadCommand(commandDownloader);
}
System.err.println("Only .bin files are supported at this time");
return false;
}
/* we need to ensure both RTS and DTR are low to start,
then pulse DTR on its own. This is the reset signal
maple responds to
*/
private void emitResetPulse() throws RunnerException {
/* wait a while for the device to reboot */
int programDelay = Preferences.getInteger("programDelay");
try {
Serial serialPort = new Serial();
// try to toggle DTR/RTS (old scheme)
serialPort.setRTS(false);
serialPort.setDTR(false);
serialPort.setDTR(true);
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
serialPort.setDTR(false);
// try magic number
serialPort.setRTS(true);
serialPort.setDTR(true);
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
serialPort.setDTR(false);
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
serialPort.write("1EAF");
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
serialPort.dispose();
} catch(Exception e) {
System.err.println("Reset via USB Serial Failed! Did you select the right serial port?\nAssuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...\n");
}
}
protected String executeCheckCommand(Collection commandDownloader)
throws RunnerException
{
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
notFoundError = false;
int result=0; // pre-initialized to quiet a bogus warning from jikes
String userdir = System.getProperty("user.dir") + File.separator;
String returnStr = new String();
try {
String[] commandArray = new String[commandDownloader.size()];
commandDownloader.toArray(commandArray);
String armBasePath;
//armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/");
armBasePath = "";
commandArray[0] = armBasePath + commandArray[0];
if (verbose || Preferences.getBoolean("upload.verbose")) {
for(int i = 0; i < commandArray.length; i++) {
System.out.print(commandArray[i] + " ");
}
System.out.println();
}
Process process = Runtime.getRuntime().exec(commandArray);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
//
boolean busy = true;
while (busy) {
try {
result = process.waitFor();
busy = false;
} catch (InterruptedException intExc) {
}
}
String s;
while ((s = stdInput.readLine()) != null) {
returnStr += s + "\n";
}
process.destroy();
if(exception!=null) {
exception.hideStackTrace();
throw exception;
}
if(result!=0) return "Error!";
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println("result2 is "+result);
// if the result isn't a known, expected value it means that something
// is fairly wrong, one possibility is that jikes has crashed.
//
if (exception != null) throw exception;
if ((result != 0) && (result != 1 )) {
exception = new RunnerException(SUPER_BADNESS);
}
return returnStr; // ? true : false;
}
// Need to overload this from Uploader to use the system-wide dfu-util
protected boolean executeUploadCommand(Collection commandDownloader)
throws RunnerException
{
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
notFoundError = false;
int result=0; // pre-initialized to quiet a bogus warning from jikes
String userdir = System.getProperty("user.dir") + File.separator;
try {
String[] commandArray = new String[commandDownloader.size()];
commandDownloader.toArray(commandArray);
String armBasePath;
//armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/");
armBasePath = "";
commandArray[0] = armBasePath + commandArray[0];
if (verbose || Preferences.getBoolean("upload.verbose")) {
for(int i = 0; i < commandArray.length; i++) {
System.out.print(commandArray[i] + " ");
}
System.out.println();
}
Process process = Runtime.getRuntime().exec(commandArray);
new MessageSiphon(process.getInputStream(), this);
new MessageSiphon(process.getErrorStream(), this);
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
//
boolean compiling = true;
while (compiling) {
try {
result = process.waitFor();
compiling = false;
} catch (InterruptedException intExc) {
}
}
if(exception!=null) {
exception.hideStackTrace();
throw exception;
}
if(result!=0)
return false;
} catch (Exception e) {
e.printStackTrace();
}
//System.out.println("result2 is "+result);
// if the result isn't a known, expected value it means that something
// is fairly wrong, one possibility is that jikes has crashed.
//
if (exception != null) throw exception;
if ((result != 0) && (result != 1 )) {
exception = new RunnerException(SUPER_BADNESS);
//editor.error(exception);
//PdeBase.openURL(BUGS_URL);
//throw new PdeException(SUPER_BADNESS);
}
return (result == 0); // ? true : false;
}
// deal with messages from dfu-util...
public void message(String s) {
if(s.indexOf("dfu-util - (C) ") != -1) { return; }
if(s.indexOf("This program is Free Software and has ABSOLUTELY NO WARRANTY") != -1) { return; }
if(s.indexOf("No DFU capable USB device found") != -1) {
System.err.print(s);
exception = new RunnerException("Problem uploading via dfu-util: No Maple found");
return;
}
if(s.indexOf("Operation not perimitted") != -1) {
System.err.print(s);
exception = new RunnerException("Problem uploading via dfu-util: Insufficient privilages");
return;
}
// else just print everything...
System.out.print(s);
}
}

View File

@ -0,0 +1,119 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package CliTemplate;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import processing.app.debug.MessageConsumer;
import processing.app.debug.MessageSiphon;
import processing.app.debug.RunnerException;
import processing.app.helpers.ProcessUtils;
/**
*
* @author cousinr
*/
public class ExecCommand implements MessageConsumer {
private boolean verbose = true;
private boolean firstErrorFound;
private boolean secondErrorFound;
private RunnerException exception;
/**
* Either succeeds or throws a RunnerException fit for public consumption.
*
* @param command
* @throws RunnerException
*/
public void execAsynchronously(String[] command) throws RunnerException {
// eliminate any empty array entries
List<String> stringList = new ArrayList<>();
for (String string : command) {
string = string.trim();
if (string.length() != 0)
stringList.add(string);
}
command = stringList.toArray(new String[stringList.size()]);
if (command.length == 0)
return;
int result = 0;
if (verbose) {
for (String c : command)
System.out.print(c + " ");
System.out.println();
}
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
Process process;
try {
process = ProcessUtils.exec(command);
} catch (IOException e) {
RunnerException re = new RunnerException(e.getMessage());
re.hideStackTrace();
throw re;
}
MessageSiphon in = new MessageSiphon(process.getInputStream(), this);
MessageSiphon err = new MessageSiphon(process.getErrorStream(), this);
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
boolean compiling = true;
while (compiling) {
try {
in.join();
err.join();
result = process.waitFor();
//System.out.println("result is " + result);
compiling = false;
} catch (InterruptedException ignored) { }
}
// an error was queued up by message(), barf this back to compile(),
// which will barf it back to Editor. if you're having trouble
// discerning the imagery, consider how cows regurgitate their food
// to digest it, and the fact that they have five stomaches.
//
//System.out.println("throwing up " + exception);
if (exception != null)
throw exception;
if (result > 1) {
// a failure in the tool (e.g. unable to locate a sub-executable)
System.err.println(MessageFormat.format("{0} returned {1}", command[0], result));
}
if (result != 0) {
RunnerException re = new RunnerException(MessageFormat.format("exit code: {0}", result));
re.hideStackTrace();
throw re;
}
}
/**
* Part of the MessageConsumer interface, this is called
* whenever a piece (usually a line) of error message is spewed
* out from the compiler. The errors are parsed for their contents
* and line number, which is then reported back to Editor.
* @param s
*/
@Override
public void message(String s) {
int i;
System.err.print(s);
}
}

View File

@ -0,0 +1,53 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-10 Ben Fry and Casey Reas
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
as published by the Free Software Foundation.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app;
/**
* The base class for the main processing application.
* Primary role of this class is for platform identification and
* general interaction with the system (launching URLs, loading
* files and images, etc) that comes from that.
*/
public class Base {
/**
* returns true if running on windows.
*/
static public boolean isWindows() {
//return PApplet.platform == PConstants.WINDOWS;
return System.getProperty("os.name").indexOf("Windows") != -1;
}
/**
* true if running on linux.
*/
static public boolean isLinux() {
//return PApplet.platform == PConstants.LINUX;
return System.getProperty("os.name").indexOf("Linux") != -1;
}
}

View File

@ -0,0 +1,157 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
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
This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app;
import java.io.*;
import java.util.*;
/**
* Storage class for user preferences and environment settings.
* <P>
* This class no longer uses the Properties class, since
* properties files are iso8859-1, which is highly likely to
* be a problem when trying to save sketch folders and locations.
* <p>
* The GUI portion in here is really ugly, as it uses exact layout. This was
* done in frustration one evening (and pre-Swing), but that's long since past,
* and it should all be moved to a proper swing layout like BoxLayout.
* <p>
* This is very poorly put together, that the preferences panel and the actual
* preferences i/o is part of the same code. But there hasn't yet been a
* compelling reason to bother with the separation aside from concern about
* being lectured by strangers who feel that it doesn't look like what they
* learned in CS class.
* <p>
* Would also be possible to change this to use the Java Preferences API.
* Some useful articles
* <a href="http://www.onjava.com/pub/a/onjava/synd/2001/10/17/j2se.html">here</a> and
* <a href="http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter10/Preferences.html">here</a>.
* However, haven't implemented this yet for lack of time, but more
* importantly, because it would entail writing to the registry (on Windows),
* or an obscure file location (on Mac OS X) and make it far more difficult to
* find the preferences to tweak them by hand (no! stay out of regedit!)
* or to reset the preferences by simply deleting the preferences.txt file.
*/
public class Preferences {
// what to call the feller
static final String PREFS_FILE = "preferences.txt";
// prompt text stuff
static final String PROMPT_YES = "Yes";
static final String PROMPT_NO = "No";
static final String PROMPT_CANCEL = "Cancel";
static final String PROMPT_OK = "OK";
static final String PROMPT_BROWSE = "Browse";
/**
* Standardized width for buttons. Mac OS X 10.3 wants 70 as its default,
* Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper.
*/
static public int BUTTON_WIDTH = 80;
/**
* Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29,
* presumably because it now includes the blue border, where it didn't
* in Java 1.3. Windows XP only wants 23 (not sure what default Linux
* would be). Because of the disparity, on Mac OS X, it will be set
* inside a static block.
*/
static public int BUTTON_HEIGHT = 24;
// value for the size bars, buttons, etc
static final int GRID_SIZE = 33;
// indents and spacing standards. these probably need to be modified
// per platform as well, since macosx is so huge, windows is smaller,
// and linux is all over the map
static final int GUI_BIG = 13;
static final int GUI_BETWEEN = 10;
static final int GUI_SMALL = 6;
// data model
static Hashtable table = new Hashtable();;
static File preferencesFile;
static protected void init(String commandLinePrefs) {
}
public Preferences() {
}
// .................................................................
// .................................................................
// .................................................................
// .................................................................
static public String get(String attribute) {
return (String) table.get(attribute);
}
static public void set(String attribute, String value) {
table.put(attribute, value);
}
static public boolean getBoolean(String attribute) {
String value = get(attribute);
return (new Boolean(value)).booleanValue();
}
static public void setBoolean(String attribute, boolean value) {
set(attribute, value ? "true" : "false");
}
static public int getInteger(String attribute) {
return Integer.parseInt(get(attribute));
}
static public void setInteger(String key, int value) {
set(key, String.valueOf(value));
}
}

View File

@ -0,0 +1,527 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
PSerial - class for serial port goodness
Part of the Processing project - http://processing.org
Copyright (c) 2004 Ben Fry & Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.app;
//import processing.core.*;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import jssc.SerialPortList;
import processing.app.debug.MessageConsumer;
public class Serial implements SerialPortEventListener {
//PApplet parent;
// properties can be passed in for default values
// otherwise defaults to 9600 N81
// these could be made static, which might be a solution
// for the classloading problem.. because if code ran again,
// the static class would have an object that could be closed
SerialPort port;
int rate;
int parity;
int databits;
int stopbits;
boolean monitor = false;
// read buffer and streams
InputStream input;
OutputStream output;
byte buffer[] = new byte[32768];
int bufferIndex;
int bufferLast;
MessageConsumer consumer;
public Serial(boolean monitor) throws SerialException {
this(Preferences.get("serial.port"),
Preferences.getInteger("serial.debug_rate"),
Preferences.get("serial.parity").charAt(0),
Preferences.getInteger("serial.databits"),
new Float(Preferences.get("serial.stopbits")).floatValue());
this.monitor = monitor;
}
public Serial() throws SerialException {
this(Preferences.get("serial.port"),
Preferences.getInteger("serial.debug_rate"),
Preferences.get("serial.parity").charAt(0),
Preferences.getInteger("serial.databits"),
new Float(Preferences.get("serial.stopbits")).floatValue());
}
public Serial(int irate) throws SerialException {
this(Preferences.get("serial.port"), irate,
Preferences.get("serial.parity").charAt(0),
Preferences.getInteger("serial.databits"),
new Float(Preferences.get("serial.stopbits")).floatValue());
}
public Serial(String iname, int irate) throws SerialException {
this(iname, irate, Preferences.get("serial.parity").charAt(0),
Preferences.getInteger("serial.databits"),
new Float(Preferences.get("serial.stopbits")).floatValue());
}
public Serial(String iname) throws SerialException {
this(iname, Preferences.getInteger("serial.debug_rate"),
Preferences.get("serial.parity").charAt(0),
Preferences.getInteger("serial.databits"),
new Float(Preferences.get("serial.stopbits")).floatValue());
}
public Serial(String iname, int irate,
char iparity, int idatabits, float istopbits)
throws SerialException {
//if (port != null) port.close();
//this.parent = parent;
//parent.attach(this);
this.rate = irate;
parity = SerialPort.PARITY_NONE;
if (iparity == 'E') parity = SerialPort.PARITY_EVEN;
if (iparity == 'O') parity = SerialPort.PARITY_ODD;
this.databits = idatabits;
stopbits = SerialPort.STOPBITS_1;
if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5;
if (istopbits == 2) stopbits = SerialPort.STOPBITS_2;
try {
port = new SerialPort(iname);
port.openPort();
port.setParams(rate, databits, stopbits, parity, true, true);
port.addEventListener(this);
} catch (Exception e) {
throw new SerialException(MessageFormat.format("Error opening serial port ''{0}''.", iname), e);
}
if (port == null) {
throw new SerialException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?");
}
}
public void setup() {
//parent.registerCall(this, DISPOSE);
}
public void dispose() throws IOException {
if (port != null) {
try {
if (port.isOpened()) {
port.closePort(); // close the port
}
} catch (SerialPortException e) {
throw new IOException(e);
} finally {
port = null;
}
}
}
public void addListener(MessageConsumer consumer) {
this.consumer = consumer;
}
public synchronized void serialEvent(SerialPortEvent serialEvent) {
if (serialEvent.isRXCHAR()) {
try {
byte[] buf = port.readBytes(serialEvent.getEventValue());
if (buf.length > 0) {
if (bufferLast == buffer.length) {
byte temp[] = new byte[bufferLast << 1];
System.arraycopy(buffer, 0, temp, 0, bufferLast);
buffer = temp;
}
if (monitor) {
System.out.print(new String(buf));
}
if (this.consumer != null) {
this.consumer.message(new String(buf));
}
}
} catch (SerialPortException e) {
errorMessage("serialEvent", e);
}
}
}
/**
* Returns the number of bytes that have been read from serial
* and are waiting to be dealt with by the user.
*/
public synchronized int available() {
return (bufferLast - bufferIndex);
}
/**
* Ignore all the bytes read so far and empty the buffer.
*/
public synchronized void clear() {
bufferLast = 0;
bufferIndex = 0;
}
/**
* Returns a number between 0 and 255 for the next byte that's
* waiting in the buffer.
* Returns -1 if there was no byte (although the user should
* first check available() to see if things are ready to avoid this)
*/
public synchronized int read() {
if (bufferIndex == bufferLast) return -1;
int outgoing = buffer[bufferIndex++] & 0xff;
if (bufferIndex == bufferLast) { // rewind
bufferIndex = 0;
bufferLast = 0;
}
return outgoing;
}
/**
* Returns the next byte in the buffer as a char.
* Returns -1, or 0xffff, if nothing is there.
*/
public synchronized char readChar() {
if (bufferIndex == bufferLast) return (char)(-1);
return (char) read();
}
/**
* Return a byte array of anything that's in the serial buffer.
* Not particularly memory/speed efficient, because it creates
* a byte array on each read, but it's easier to use than
* readBytes(byte b[]) (see below).
*/
public synchronized byte[] readBytes() {
if (bufferIndex == bufferLast) return null;
int length = bufferLast - bufferIndex;
byte outgoing[] = new byte[length];
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
bufferIndex = 0; // rewind
bufferLast = 0;
return outgoing;
}
/**
* Grab whatever is in the serial buffer, and stuff it into a
* byte buffer passed in by the user. This is more memory/time
* efficient than readBytes() returning a byte[] array.
* <p/>
* Returns an int for how many bytes were read. If more bytes
* are available than can fit into the byte array, only those
* that will fit are read.
*/
public synchronized int readBytes(byte outgoing[]) {
if (bufferIndex == bufferLast) return 0;
int length = bufferLast - bufferIndex;
if (length > outgoing.length) length = outgoing.length;
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
bufferIndex += length;
if (bufferIndex == bufferLast) {
bufferIndex = 0; // rewind
bufferLast = 0;
}
return length;
}
/**
* Reads from the serial port into a buffer of bytes up to and
* including a particular character. If the character isn't in
* the serial buffer, then 'null' is returned.
*/
public synchronized byte[] readBytesUntil(int interesting) {
if (bufferIndex == bufferLast) return null;
byte what = (byte)interesting;
int found = -1;
for (int k = bufferIndex; k < bufferLast; k++) {
if (buffer[k] == what) {
found = k;
break;
}
}
if (found == -1) return null;
int length = found - bufferIndex + 1;
byte outgoing[] = new byte[length];
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
bufferIndex = 0; // rewind
bufferLast = 0;
return outgoing;
}
/**
* Reads from the serial port into a buffer of bytes until a
* particular character. If the character isn't in the serial
* buffer, then 'null' is returned.
* <p/>
* If outgoing[] is not big enough, then -1 is returned,
* and an error message is printed on the console.
* If nothing is in the buffer, zero is returned.
* If 'interesting' byte is not in the buffer, then 0 is returned.
*/
public synchronized int readBytesUntil(int interesting, byte outgoing[]) {
if (bufferIndex == bufferLast) return 0;
byte what = (byte)interesting;
int found = -1;
for (int k = bufferIndex; k < bufferLast; k++) {
if (buffer[k] == what) {
found = k;
break;
}
}
if (found == -1) return 0;
int length = found - bufferIndex + 1;
if (length > outgoing.length) {
System.err.println("readBytesUntil() byte buffer is" +
" too small for the " + length +
" bytes up to and including char " + interesting);
return -1;
}
//byte outgoing[] = new byte[length];
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
bufferIndex += length;
if (bufferIndex == bufferLast) {
bufferIndex = 0; // rewind
bufferLast = 0;
}
return length;
}
/**
* Return whatever has been read from the serial port so far
* as a String. It assumes that the incoming characters are ASCII.
* <p/>
* If you want to move Unicode data, you can first convert the
* String to a byte stream in the representation of your choice
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
*/
public synchronized String readString() {
if (bufferIndex == bufferLast) return null;
return new String(readBytes());
}
/**
* Combination of readBytesUntil and readString. See caveats in
* each function. Returns null if it still hasn't found what
* you're looking for.
* <p/>
* If you want to move Unicode data, you can first convert the
* String to a byte stream in the representation of your choice
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
*/
public synchronized String readStringUntil(int interesting) {
byte b[] = readBytesUntil(interesting);
if (b == null) return null;
return new String(b);
}
/**
* This will handle both ints, bytes and chars transparently.
*/
public void write(int what) { // will also cover char
try {
port.writeInt(what & 0xff);
} catch (SerialPortException e) {
errorMessage("write", e);
}
}
public void write(byte bytes[]) {
try {
port.writeBytes(bytes);
} catch (SerialPortException e) {
errorMessage("write", e);
}
}
/**
* Write a String to the output. Note that this doesn't account
* for Unicode (two bytes per char), nor will it send UTF8
* characters.. It assumes that you mean to send a byte buffer
* (most often the case for networking and serial i/o) and
* will only use the bottom 8 bits of each char in the string.
* (Meaning that internally it uses String.getBytes)
* <p/>
* If you want to move Unicode data, you can first convert the
* String to a byte stream in the representation of your choice
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
*/
public void write(String what) {
write(what.getBytes());
}
public void setDTR(boolean state) {
try {
port.setDTR(state);
} catch (SerialPortException e) {
errorMessage("setDTR", e);
}
}
public void setRTS(boolean state) {
try {
port.setRTS(state);
} catch (SerialPortException e) {
errorMessage("setRTS", e);
}
}
static public List<String> list() {
return Arrays.asList(SerialPortList.getPortNames());
}
/**
* General error reporting, all corraled here just in case
* I think of something slightly more intelligent to do.
*/
static public void errorMessage(String where, Throwable e) {
System.err.println("Error inside Serial." + where + "()");
e.printStackTrace();
}
}
/*
class SerialMenuListener implements ItemListener {
//public SerialMenuListener() { }
public void itemStateChanged(ItemEvent e) {
int count = serialMenu.getItemCount();
for (int i = 0; i < count; i++) {
((CheckboxMenuItem)serialMenu.getItem(i)).setState(false);
}
CheckboxMenuItem item = (CheckboxMenuItem)e.getSource();
item.setState(true);
String name = item.getLabel();
//System.out.println(item.getLabel());
PdeBase.properties.put("serial.port", name);
//System.out.println("set to " + get("serial.port"));
}
}
*/
/*
protected Vector buildPortList() {
// get list of names for serial ports
// have the default port checked (if present)
Vector list = new Vector();
//SerialMenuListener listener = new SerialMenuListener();
boolean problem = false;
// if this is failing, it may be because
// lib/javax.comm.properties is missing.
// java is weird about how it searches for java.comm.properties
// so it tends to be very fragile. i.e. quotes in the CLASSPATH
// environment variable will hose things.
try {
//System.out.println("building port list");
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
CommPortIdentifier portId =
(CommPortIdentifier) portList.nextElement();
//System.out.println(portId);
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
//if (portId.getName().equals(port)) {
String name = portId.getName();
//CheckboxMenuItem mi =
//new CheckboxMenuItem(name, name.equals(defaultName));
//mi.addItemListener(listener);
//serialMenu.add(mi);
list.addElement(name);
}
}
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
problem = true;
} catch (Exception e) {
System.out.println("exception building serial menu");
e.printStackTrace();
}
//if (serialMenu.getItemCount() == 0) {
//System.out.println("dimming serial menu");
//serialMenu.setEnabled(false);
//}
// only warn them if this is the first time
if (problem && PdeBase.firstTime) {
JOptionPane.showMessageDialog(this, //frame,
"Serial port support not installed.\n" +
"Check the readme for instructions\n" +
"if you need to use the serial port. ",
"Serial Port Warning",
JOptionPane.WARNING_MESSAGE);
}
return list;
}
*/

View File

@ -0,0 +1,39 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Copyright (c) 2007 David A. Mellis
This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app;
public class SerialException extends Exception {
public SerialException() {
super();
}
public SerialException(String message) {
super(message);
}
public SerialException(String message, Throwable cause) {
super(message, cause);
}
public SerialException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,42 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
/**
* Interface for dealing with parser/compiler output.
* <P>
* Different instances of MessageStream need to do different things with
* messages. In particular, a stream instance used for parsing output from
* the compiler compiler has to interpret its messages differently than one
* parsing output from the runtime.
* <P>
* Classes which consume messages and do something with them
* should implement this interface.
*/
public interface MessageConsumer {
public void message(String s);
}

View File

@ -0,0 +1,104 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
/**
* Slurps up messages from compiler.
*/
public class MessageSiphon implements Runnable {
private final BufferedReader streamReader;
private final MessageConsumer consumer;
private Thread thread;
private boolean canRun;
public MessageSiphon(InputStream stream, MessageConsumer consumer) {
this.streamReader = new BufferedReader(new InputStreamReader(stream));
this.consumer = consumer;
this.canRun = true;
thread = new Thread(this);
// don't set priority too low, otherwise exceptions won't
// bubble up in time (i.e. compile errors have a weird delay)
//thread.setPriority(Thread.MIN_PRIORITY);
thread.setPriority(Thread.MAX_PRIORITY - 1);
thread.start();
}
public void run() {
try {
// process data until we hit EOF; this will happily block
// (effectively sleeping the thread) until new data comes in.
// when the program is finally done, null will come through.
//
String currentLine;
while (canRun && (currentLine = streamReader.readLine()) != null) {
// \n is added again because readLine() strips it out
//EditorConsole.systemOut.println("messaging in");
consumer.message(currentLine + "\n");
//EditorConsole.systemOut.println("messaging out");
}
//EditorConsole.systemOut.println("messaging thread done");
} catch (NullPointerException npe) {
// Fairly common exception during shutdown
} catch (SocketException e) {
// socket has been close while we were wainting for data. nothing to see here, move along
} catch (Exception e) {
// On Linux and sometimes on Mac OS X, a "bad file descriptor"
// message comes up when closing an applet that's run externally.
// That message just gets supressed here..
String mess = e.getMessage();
if ((mess != null) &&
(mess.indexOf("Bad file descriptor") != -1)) {
//if (e.getMessage().indexOf("Bad file descriptor") == -1) {
//System.err.println("MessageSiphon err " + e);
//e.printStackTrace();
} else {
e.printStackTrace();
}
} finally {
thread = null;
}
}
// Wait until the MessageSiphon thread is complete.
public void join() throws java.lang.InterruptedException {
// Grab a temp copy in case another thread nulls the "thread"
// member variable
Thread t = thread;
if (t != null) t.join();
}
public void stop() {
this.canRun = false;
}
}

View File

@ -0,0 +1,161 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas
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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
/**
* An exception with a line number attached that occurs
* during either compile time or run time.
*/
@SuppressWarnings("serial")
public class RunnerException extends Exception {
protected String message;
protected int codeIndex;
protected int codeLine;
protected int codeColumn;
protected boolean showStackTrace;
public RunnerException(String message) {
this(message, true);
}
public RunnerException(String message, boolean showStackTrace) {
this(message, -1, -1, -1, showStackTrace);
}
public RunnerException(String message, int file, int line) {
this(message, file, line, -1, true);
}
public RunnerException(String message, int file, int line, int column) {
this(message, file, line, column, true);
}
public RunnerException(String message, int file, int line, int column,
boolean showStackTrace) {
this.message = message;
this.codeIndex = file;
this.codeLine = line;
this.codeColumn = column;
this.showStackTrace = showStackTrace;
}
public RunnerException(Exception e) {
super(e);
this.showStackTrace = true;
}
/**
* Override getMessage() in Throwable, so that I can set
* the message text outside the constructor.
*/
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getCodeIndex() {
return codeIndex;
}
public void setCodeIndex(int index) {
codeIndex = index;
}
public boolean hasCodeIndex() {
return codeIndex != -1;
}
public int getCodeLine() {
return codeLine;
}
public void setCodeLine(int line) {
this.codeLine = line;
}
public boolean hasCodeLine() {
return codeLine != -1;
}
public void setCodeColumn(int column) {
this.codeColumn = column;
}
public int getCodeColumn() {
return codeColumn;
}
public void showStackTrace() {
showStackTrace = true;
}
public void hideStackTrace() {
showStackTrace = false;
}
/**
* Nix the java.lang crap out of an exception message
* because it scares the children.
* <P>
* This function must be static to be used with super()
* in each of the constructors above.
*/
/*
static public final String massage(String msg) {
if (msg.indexOf("java.lang.") == 0) {
//int dot = msg.lastIndexOf('.');
msg = msg.substring("java.lang.".length());
}
return msg;
//return (dot == -1) ? msg : msg.substring(dot+1);
}
*/
public void printStackTrace() {
if (showStackTrace) {
super.printStackTrace();
}
}
}

View File

@ -0,0 +1,32 @@
package processing.app.helpers;
//import processing.app.Base;
import java.io.IOException;
import java.util.Map;
import processing.app.Base;
public class ProcessUtils {
public static Process exec(String[] command) throws IOException {
// No problems on linux and mac
if (!Base.isWindows()) {
return Runtime.getRuntime().exec(command);
}
// Brutal hack to workaround windows command line parsing.
// http://stackoverflow.com/questions/5969724/java-runtime-exec-fails-to-escape-characters-properly
// http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
// http://bugs.sun.com/view_bug.do?bug_id=6468220
// http://bugs.sun.com/view_bug.do?bug_id=6518827
String[] cmdLine = new String[command.length];
for (int i = 0; i < command.length; i++)
cmdLine[i] = command[i].replace("\"", "\\\"");
ProcessBuilder pb = new ProcessBuilder(cmdLine);
Map<String, String> env = pb.environment();
env.put("CYGWIN", "nodosfilewarning");
return pb.start();
}
}