change folder structure and control files to newest concept
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>processing-dxf</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,12 @@
|
||||
#Sat Nov 12 10:56:00 CST 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Processing DXF Library" default="build">
|
||||
|
||||
<target name="clean" description="Clean the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="library/dxf.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../../../core/library/core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built" message="Please build the core library first and make sure it sits in ../../../core/library/core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
<javac source="1.8"
|
||||
target="1.8"
|
||||
srcdir="src" destdir="bin"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/library/core.jar"
|
||||
nowarn="true"
|
||||
compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
|
||||
<compilerclasspath path="../../mode/org.eclipse.jdt.core.jar;
|
||||
../../mode/jdtCompilerAdapter.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build DXF library">
|
||||
<jar basedir="bin" destfile="library/dxf.jar" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Simple DXF Export
|
||||
* by Simon Greenwold.
|
||||
*
|
||||
* Press the 'R' key to export a DXF file.
|
||||
*/
|
||||
|
||||
|
||||
import processing.dxf.*;
|
||||
boolean record = false;
|
||||
|
||||
void setup() {
|
||||
size(400, 400, P3D);
|
||||
noStroke();
|
||||
sphereDetail(12);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (record == true) {
|
||||
beginRaw(DXF, "output.dxf"); // Start recording to the file
|
||||
}
|
||||
lights();
|
||||
background(0);
|
||||
translate(width / 3, height / 3, -200);
|
||||
rotateZ(map(mouseY, 0, height, 0, PI));
|
||||
rotateY(map(mouseX, 0, width, 0, HALF_PI));
|
||||
for (int y = -2; y < 2; y++) {
|
||||
for (int x = -2; x < 2; x++) {
|
||||
for (int z = -2; z < 2; z++) {
|
||||
pushMatrix();
|
||||
translate(120*x, 120*y, -120*z);
|
||||
sphere(30);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (record == true) {
|
||||
endRaw();
|
||||
record = false; // Stop recording to the file
|
||||
}
|
||||
}
|
||||
|
||||
void keyPressed() {
|
||||
if (key == 'R' || key == 'r') { // Press R to save the file
|
||||
record = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
name = DXF Export
|
||||
version = 1
|
||||
@@ -0,0 +1,403 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
* RawDXF - Code to write DXF files with beginRaw/endRaw
|
||||
* An extension for the Processing project - http://processing.org
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with the Processing project; if not,
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
* Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.dxf;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
/**
|
||||
* A simple library to write DXF files with Processing.
|
||||
* Because this is used with beginRaw() and endRaw(), only individual
|
||||
* triangles and (discontinuous) line segments will be written to the file.
|
||||
* <p>
|
||||
* Use something like a keyPressed() in PApplet to trigger it,
|
||||
* to avoid writing a bazillion .dxf files.
|
||||
* <p>
|
||||
* Usually, the file will be saved to the sketch's folder.
|
||||
* Use Sketch → Show Sketch Folder to see it from the PDE.
|
||||
* <p>
|
||||
* A simple example of how to use:
|
||||
* <PRE>
|
||||
* import processing.dxf.*;
|
||||
*
|
||||
* boolean record;
|
||||
*
|
||||
* void setup() {
|
||||
* size(500, 500, P3D);
|
||||
* }
|
||||
*
|
||||
* void keyPressed() {
|
||||
* // use a key press so that it doesn't make a million files
|
||||
* if (key == 'r') record = true;
|
||||
* }
|
||||
*
|
||||
* void draw() {
|
||||
* if (record) {
|
||||
* beginRaw(DXF, "output.dxf");
|
||||
* }
|
||||
*
|
||||
* // do all your drawing here
|
||||
*
|
||||
* if (record) {
|
||||
* endRaw();
|
||||
* record = false;
|
||||
* }
|
||||
* }
|
||||
* </PRE>
|
||||
* or to use it and be able to control the current layer:
|
||||
* <PRE>
|
||||
* import processing.dxf.*;
|
||||
*
|
||||
* boolean record;
|
||||
* RawDXF dxf;
|
||||
*
|
||||
* void setup() {
|
||||
* size(500, 500, P3D);
|
||||
* }
|
||||
*
|
||||
* void keyPressed() {
|
||||
* // use a key press so that it doesn't make a million files
|
||||
* if (key == 'r') record = true;
|
||||
* }
|
||||
*
|
||||
* void draw() {
|
||||
* if (record) {
|
||||
* dxf = (RawDXF) createGraphics(width, height, DXF, "output.dxf");
|
||||
* beginRaw(dxf);
|
||||
* }
|
||||
*
|
||||
* // do all your drawing here, and to set the layer, call:
|
||||
* // if (record) {
|
||||
* // dxf.setLayer(num);
|
||||
* // }
|
||||
* // where 'num' is an integer.
|
||||
* // the default is zero, or you can set it to whatever.
|
||||
*
|
||||
* if (record) {
|
||||
* endRaw();
|
||||
* record = false;
|
||||
* dxf = null;
|
||||
* }
|
||||
* }
|
||||
* </PRE>
|
||||
* Note that even though this class is a subclass of PGraphics, it only
|
||||
* implements the parts of the API that are necessary for beginRaw/endRaw.
|
||||
* <p>
|
||||
* Based on the original DXF writer from Simon Greenwold, February 2004.
|
||||
* Updated for Processing 0070 by Ben Fry in September 2004,
|
||||
* and again for Processing beta in April 2005.
|
||||
* Rewritten to support beginRaw/endRaw by Ben Fry in February 2006.
|
||||
* Updated again for inclusion as a core library in March 2006.
|
||||
* Constructor modifications in September 2008 as we approach 1.0.
|
||||
*/
|
||||
public class RawDXF extends PGraphics {
|
||||
|
||||
File file;
|
||||
PrintWriter writer;
|
||||
int currentLayer;
|
||||
|
||||
|
||||
public RawDXF() { }
|
||||
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
if (path != null) {
|
||||
file = new File(path);
|
||||
if (!file.isAbsolute()) file = null;
|
||||
}
|
||||
if (file == null) {
|
||||
throw new RuntimeException("DXF export requires an absolute path " +
|
||||
"for the location of the output file.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ..............................................................
|
||||
|
||||
|
||||
protected void allocate() {
|
||||
/*
|
||||
for (int i = 0; i < MAX_TRI_LAYERS; i++) {
|
||||
layerList[i] = NO_LAYER;
|
||||
}
|
||||
*/
|
||||
setLayer(0);
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
writeFooter();
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
writer = null;
|
||||
}
|
||||
|
||||
|
||||
public boolean displayable() {
|
||||
return false; // just in case someone wants to use this on its own
|
||||
}
|
||||
|
||||
|
||||
public boolean is2D() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean is3D() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ..............................................................
|
||||
|
||||
|
||||
public void beginDraw() {
|
||||
// have to create file object here, because the name isn't yet
|
||||
// available in allocate()
|
||||
if (writer == null) {
|
||||
try {
|
||||
writer = new PrintWriter(new FileWriter(file));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e); // java 1.4+
|
||||
}
|
||||
writeHeader();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void endDraw() {
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
|
||||
// ..............................................................
|
||||
|
||||
|
||||
/**
|
||||
* Set the current layer being used in the DXF file.
|
||||
* The default is zero.
|
||||
*/
|
||||
public void setLayer(int layer) {
|
||||
currentLayer = layer;
|
||||
}
|
||||
|
||||
|
||||
// ..............................................................
|
||||
|
||||
|
||||
private void writeHeader() {
|
||||
writer.println("0");
|
||||
writer.println("SECTION");
|
||||
writer.println("2");
|
||||
writer.println("ENTITIES");
|
||||
}
|
||||
|
||||
|
||||
private void writeFooter() {
|
||||
writer.println("0");
|
||||
writer.println("ENDSEC");
|
||||
writer.println("0");
|
||||
writer.println("EOF");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a command on one line (as a String), then start a new line
|
||||
* and write out a formatted float. Available for anyone who wants to
|
||||
* insert additional commands into the DXF stream.
|
||||
*/
|
||||
public void write(String cmd, float val) {
|
||||
writer.println(cmd);
|
||||
// Don't number format, will cause trouble on systems that aren't en-US
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=495
|
||||
writer.println(val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a line to the dxf file. Available for anyone who wants to
|
||||
* insert additional commands into the DXF stream.
|
||||
*/
|
||||
public void println(String what) {
|
||||
writer.println(what);
|
||||
}
|
||||
|
||||
|
||||
protected void writeLine(int index1, int index2) {
|
||||
writer.println("0");
|
||||
writer.println("LINE");
|
||||
|
||||
// write out the layer
|
||||
writer.println("8");
|
||||
writer.println(String.valueOf(currentLayer));
|
||||
|
||||
write("10", vertices[index1][X]);
|
||||
write("20", vertices[index1][Y]);
|
||||
write("30", vertices[index1][Z]);
|
||||
|
||||
write("11", vertices[index2][X]);
|
||||
write("21", vertices[index2][Y]);
|
||||
write("31", vertices[index2][Z]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
protected void writeLineStrip() {
|
||||
writeLine();
|
||||
// shift the last vertex to be the first vertex
|
||||
System.arraycopy(vertices[1], 0, vertices[0], 0, vertices[1].length);
|
||||
vertexCount = 1;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
protected void writeTriangle() {
|
||||
writer.println("0");
|
||||
writer.println("3DFACE");
|
||||
|
||||
// write out the layer
|
||||
writer.println("8");
|
||||
/*
|
||||
if (i < MAX_TRI_LAYERS) {
|
||||
if (layerList[i] >= 0) {
|
||||
currentLayer = layerList[i];
|
||||
}
|
||||
}
|
||||
*/
|
||||
writer.println(String.valueOf(currentLayer));
|
||||
|
||||
write("10", vertices[0][X]);
|
||||
write("20", vertices[0][Y]);
|
||||
write("30", vertices[0][Z]);
|
||||
|
||||
write("11", vertices[1][X]);
|
||||
write("21", vertices[1][Y]);
|
||||
write("31", vertices[1][Z]);
|
||||
|
||||
write("12", vertices[2][X]);
|
||||
write("22", vertices[2][Y]);
|
||||
write("32", vertices[2][Z]);
|
||||
|
||||
// Without adding EPSILON, Rhino kinda freaks out.
|
||||
// A face is actually a quad, not a triangle,
|
||||
// so instead kinda fudging the final point here.
|
||||
write("13", vertices[2][X] + EPSILON);
|
||||
write("23", vertices[2][Y] + EPSILON);
|
||||
write("33", vertices[2][Z] + EPSILON);
|
||||
|
||||
vertexCount = 0;
|
||||
}
|
||||
|
||||
|
||||
// ..............................................................
|
||||
|
||||
|
||||
public void beginShape(int kind) {
|
||||
shape = kind;
|
||||
|
||||
if ((shape != LINES) &&
|
||||
(shape != TRIANGLES) &&
|
||||
(shape != POLYGON)) {
|
||||
String err =
|
||||
"RawDXF can only be used with beginRaw(), " +
|
||||
"because it only supports lines and triangles";
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
if ((shape == POLYGON) && fill) {
|
||||
throw new RuntimeException("DXF Export only supports non-filled shapes.");
|
||||
}
|
||||
|
||||
vertexCount = 0;
|
||||
}
|
||||
|
||||
|
||||
public void vertex(float x, float y) {
|
||||
vertex(x, y, 0);
|
||||
}
|
||||
|
||||
|
||||
public void vertex(float x, float y, float z) {
|
||||
float vertex[] = vertices[vertexCount];
|
||||
|
||||
vertex[X] = x; // note: not mx, my, mz like PGraphics3
|
||||
vertex[Y] = y;
|
||||
vertex[Z] = z;
|
||||
|
||||
if (fill) {
|
||||
vertex[R] = fillR;
|
||||
vertex[G] = fillG;
|
||||
vertex[B] = fillB;
|
||||
vertex[A] = fillA;
|
||||
}
|
||||
|
||||
if (stroke) {
|
||||
vertex[SR] = strokeR;
|
||||
vertex[SG] = strokeG;
|
||||
vertex[SB] = strokeB;
|
||||
vertex[SA] = strokeA;
|
||||
vertex[SW] = strokeWeight;
|
||||
}
|
||||
|
||||
if (textureImage != null) { // for the future?
|
||||
vertex[U] = textureU;
|
||||
vertex[V] = textureV;
|
||||
}
|
||||
vertexCount++;
|
||||
|
||||
if ((shape == LINES) && (vertexCount == 2)) {
|
||||
writeLine(0, 1);
|
||||
vertexCount = 0;
|
||||
|
||||
/*
|
||||
} else if ((shape == LINE_STRIP) && (vertexCount == 2)) {
|
||||
writeLineStrip();
|
||||
*/
|
||||
|
||||
} else if ((shape == TRIANGLES) && (vertexCount == 3)) {
|
||||
writeTriangle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void endShape(int mode) {
|
||||
if (shape == POLYGON) {
|
||||
for (int i = 0; i < vertexCount - 1; i++) {
|
||||
writeLine(i, i+1);
|
||||
}
|
||||
if (mode == CLOSE) {
|
||||
writeLine(vertexCount - 1, 0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
if ((vertexCount != 0) &&
|
||||
((shape != LINE_STRIP) && (vertexCount != 1))) {
|
||||
System.err.println("Extra vertex boogers found.");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Processing Hardware I/O Library" default="build">
|
||||
|
||||
<target name="clean" description="Clean the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="library/io.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../../../core/library/core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built" message="Please build the core library first and make sure it sits in ../../../core/library/core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
<javac source="1.8"
|
||||
target="1.8"
|
||||
srcdir="src" destdir="bin"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/library/core.jar"
|
||||
nowarn="true"
|
||||
compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
|
||||
<compilerclasspath path="../../mode/org.eclipse.jdt.core.jar;
|
||||
../../mode/jdtCompilerAdapter.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build I/O library">
|
||||
<jar basedir="bin" destfile="library/io.jar" />
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="build" description="Package standalone library">
|
||||
<!-- set revision number as library version -->
|
||||
<loadfile srcfile="../../../todo.txt" property="revision">
|
||||
<filterchain>
|
||||
<headfilter lines="1"/>
|
||||
<tokenfilter>
|
||||
<stringtokenizer suppressdelims="true"/>
|
||||
<!-- grab the thing from the first line that's 4 digits -->
|
||||
<containsregex pattern="(\d\d\d\d)" />
|
||||
</tokenfilter>
|
||||
</filterchain>
|
||||
</loadfile>
|
||||
<replaceregexp file="library.properties" match="version = .*" replace="version = ${revision}" flags="g" />
|
||||
<replaceregexp file="library.properties" match="prettyVersion = .*" replace="prettyVersion = ${revision}" flags="g" />
|
||||
|
||||
<get src="http://download.processing.org/reference.zip"
|
||||
dest="reference.zip"
|
||||
usetimestamp="true" />
|
||||
<mkdir dir="reference" />
|
||||
<unzip dest="."
|
||||
src="reference.zip"
|
||||
overwrite="true">
|
||||
<patternset>
|
||||
<include name="reference/css/**" />
|
||||
<include name="reference/img/**" />
|
||||
<include name="reference/javascript/**" />
|
||||
<include name="reference/libraries/io/**" />
|
||||
</patternset>
|
||||
</unzip>
|
||||
<delete file="reference.zip" />
|
||||
<echo file="reference/index.html" message="<html><head><meta http-equiv='refresh' content='0; url=libraries/io/index.html'></head><body></body></html>" />
|
||||
|
||||
<zip destfile="../io.zip">
|
||||
<zipfileset dir="." prefix="io">
|
||||
<exclude name="bin/**"/>
|
||||
</zipfileset>
|
||||
</zip>
|
||||
|
||||
<copy file="library.properties"
|
||||
toFile="../io.txt"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,107 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// ADS1015 and ADS1115 are Analog-to-Digital converters using I2C
|
||||
// they have four channels and 12 and 16 bits of resolution respectively
|
||||
// datasheets: http://www.ti.com/lit/ds/symlink/ads1015.pdf
|
||||
// http://www.ti.com/lit/ds/symlink/ads1115.pdf
|
||||
|
||||
class ADS1015 extends ADS1X15 {
|
||||
ADS1015(String dev, int address) {
|
||||
super(dev, address);
|
||||
bitShift = 4;
|
||||
conversionDelay = 1;
|
||||
}
|
||||
|
||||
// returns a number between -1.0 and 1.0
|
||||
float analogRead(int channel) {
|
||||
return readSingleEnded(channel) / 2047.0;
|
||||
}
|
||||
}
|
||||
|
||||
class ADS1115 extends ADS1X15 {
|
||||
ADS1115(String dev, int address) {
|
||||
super(dev, address);
|
||||
bitShift = 0;
|
||||
conversionDelay = 8;
|
||||
}
|
||||
|
||||
// returns a number between -1.0 and 1.0
|
||||
float analogRead(int channel) {
|
||||
return readSingleEnded(channel) / 32767.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ADS1X15 extends I2C {
|
||||
int address;
|
||||
int bitShift; // bits to shift the result to the right
|
||||
int conversionDelay; // in ms
|
||||
int channel; // last channel used
|
||||
int range; // see below
|
||||
|
||||
// possible voltage ranges
|
||||
static final int INTERNAL_6V144 = 0; // +/- 6.144V
|
||||
static final int INTERNAL_4V096 = 1; // +/- 4.096V (library default)
|
||||
static final int INTERNAL_2V048 = 2; // +/- 2.048V
|
||||
static final int INTERNAL_1V024 = 3; // +/- 1.024V
|
||||
static final int INTERNAL_0V512 = 4; // +/- 0.512V
|
||||
static final int INTERNAL_0V256 = 5; // +/- 0.256V
|
||||
|
||||
ADS1X15(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
this.channel = -1;
|
||||
this.range = INTERNAL_4V096;
|
||||
}
|
||||
|
||||
// be careful not to make the input voltage exceed VCC + 0.3V
|
||||
// this is regardless of the selected input range
|
||||
void analogReference(int type) {
|
||||
if (type < 0 || 7 < type) {
|
||||
throw new RuntimeException("Invalid range setting");
|
||||
}
|
||||
range = type;
|
||||
}
|
||||
|
||||
int readSingleEnded(int channel) {
|
||||
if (channel < 0 || 3 < channel) {
|
||||
System.err.println("The channel needs to be from 0 to 3");
|
||||
throw new IllegalArgumentException("Unexpected channel");
|
||||
}
|
||||
|
||||
if (channel != this.channel) {
|
||||
int config = 0x0183; // start with the default value from datasheet
|
||||
config &= ~0x100; // enable continuous readings
|
||||
config |= (range << 9); // set selected range (gain)
|
||||
config |= (1 << 14) | (channel << 12); // set single-ended and channel
|
||||
config |= (1 << 15); // start a single conversion
|
||||
writeRegister(0x01, config); // write to the configuration register at 0x01
|
||||
|
||||
// when the channel switched we need to wait for the upcoming
|
||||
// conversion to finish
|
||||
delay(conversionDelay);
|
||||
|
||||
// save the channel so that we don't need to do the same for
|
||||
// subsequent reads from the same channel
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
return readS16(0x00) >> bitShift; // read from the conversion register at 0x00
|
||||
// the ADS1015 will have its 12-bit result in the upper bits, shift those right by four
|
||||
}
|
||||
|
||||
protected void writeRegister(int register, int value) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
write(value >> 8);
|
||||
write(value & 0xFF);
|
||||
endTransmission();
|
||||
}
|
||||
|
||||
protected int readS16(int register) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
byte[] in = read(2);
|
||||
return (in[0] << 8) | in[1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import processing.io.*;
|
||||
ADS1015 adc;
|
||||
// or, alternatively:
|
||||
// ADS1115 adc;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
//printArray(I2C.list());
|
||||
|
||||
adc = new ADS1015("i2c-1", 0x48);
|
||||
//adc = new ADS1115("i2c-1", 0x48);
|
||||
|
||||
// this sets the measuring range to +/- 4.096 Volts
|
||||
// other ranges supported by this chip:
|
||||
// INTERNAL_6V144, INTERNAL_2V048, INTERNAL_1V024,
|
||||
// INTERNAL_0V512, INTERNAL_0V256
|
||||
adc.analogReference(ADS1X15.INTERNAL_4V096);
|
||||
|
||||
// Important: do not attempt to measure voltages higher than
|
||||
// the supply voltage (VCC) + 0.3V, meaning that 3.6V is the
|
||||
// absolut maximum voltage on the Raspberry Pi. This is
|
||||
// irrespective of the analogReference() setting above.
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// this will return a number between 0 and 1
|
||||
// (as long as your voltage is positive)
|
||||
float measured = adc.analogRead(0);
|
||||
|
||||
// multiply with the selected range to get the absolut voltage
|
||||
float volts = measured * 4.096;
|
||||
println("Analog Input 0 is " + volts + "V");
|
||||
|
||||
background(255);
|
||||
fill(measured * 255);
|
||||
ellipse(width/2, height/2, width * 0.75, width * 0.75);
|
||||
}
|
||||
|
After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,20 @@
|
||||
import processing.io.*;
|
||||
MCP3001 adc;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
//printArray(SPI.list());
|
||||
adc = new MCP3001(SPI.list()[0]);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// this will return a number between 0 and 1
|
||||
float measured = adc.analogRead();
|
||||
|
||||
// multiply with the supply voltage to get an absolute value
|
||||
float volts = 3.3 * measured;
|
||||
println("Analog Input is " + volts + "V");
|
||||
|
||||
background(measured * 255);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import processing.io.SPI;
|
||||
|
||||
// MCP3001 is a Analog-to-Digital converter using SPI
|
||||
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf
|
||||
|
||||
class MCP3001 extends SPI {
|
||||
|
||||
MCP3001(String dev) {
|
||||
super(dev);
|
||||
settings(500000, SPI.MSBFIRST, SPI.MODE0);
|
||||
}
|
||||
|
||||
// returns a number between 0.0 and 1.0
|
||||
float analogRead() {
|
||||
// dummy write, actual values don't matter
|
||||
byte[] out = { 0, 0 };
|
||||
byte[] in = transfer(out);
|
||||
// some input bit shifting according to the datasheet p. 16
|
||||
int val = ((in[0] & 0x1f) << 5) | ((in[1] & 0xf8) >> 3);
|
||||
// val is between 0 and 1023
|
||||
return val/1023.0;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,22 @@
|
||||
import processing.io.*;
|
||||
MCP3008 adc;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
//printArray(SPI.list());
|
||||
adc = new MCP3008(SPI.list()[0]);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// this will return a number between 0 and 1
|
||||
float measured = adc.analogRead(0);
|
||||
|
||||
// multiply with the supply voltage to get an absolute value
|
||||
float volts = 3.3 * measured;
|
||||
println("Analog Input 0 is " + volts + "V");
|
||||
|
||||
background(255);
|
||||
fill(measured * 255);
|
||||
ellipse(width/2, height/2, width * 0.75, width * 0.75);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import processing.io.SPI;
|
||||
|
||||
// MCP3008 is a Analog-to-Digital converter using SPI
|
||||
// other than the MCP3001, this has 8 input channels
|
||||
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf
|
||||
|
||||
class MCP3008 extends SPI {
|
||||
|
||||
MCP3008(String dev) {
|
||||
super(dev);
|
||||
settings(500000, SPI.MSBFIRST, SPI.MODE0);
|
||||
}
|
||||
|
||||
// returns a number between 0.0 and 1.0
|
||||
float analogRead(int channel) {
|
||||
if (channel < 0 || 7 < channel) {
|
||||
System.err.println("The channel needs to be from 0 to 7");
|
||||
throw new IllegalArgumentException("Unexpected channel");
|
||||
}
|
||||
byte[] out = { 0, 0, 0 };
|
||||
// encode the channel number in the first byte
|
||||
out[0] = (byte)(0x18 | channel);
|
||||
byte[] in = transfer(out);
|
||||
int val = ((in[1] & 0x03) << 8) | (in[2] & 0xff);
|
||||
// val is between 0 and 1023
|
||||
return val/1023.0;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,19 @@
|
||||
import processing.io.*;
|
||||
HMC6352 compass;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
// the module's I2C address can be changed by modifying values in its EEPROM
|
||||
// 0x21 is however the default address
|
||||
|
||||
//printArray(I2C.list());
|
||||
compass = new HMC6352("i2c-1", 0x21);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
float deg = compass.heading();
|
||||
println(deg + " degrees");
|
||||
line(width/2, height/2, width/2+sin(radians(deg))*width/2, height/2-cos(radians(deg))*height/2);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// HMC6352 is a digital compass using I2C
|
||||
// datasheet: https://www.sparkfun.com/datasheets/Components/HMC6352.pdf
|
||||
|
||||
class HMC6352 extends I2C {
|
||||
int address;
|
||||
|
||||
HMC6352(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
setHeadingMode();
|
||||
}
|
||||
|
||||
void setHeadingMode() {
|
||||
beginTransmission(address);
|
||||
// command byte for writing to EEPROM
|
||||
write(0x77);
|
||||
// address of the output data control byte
|
||||
write(0x4e);
|
||||
// give us the plain heading
|
||||
write(0x00);
|
||||
endTransmission();
|
||||
}
|
||||
|
||||
float heading() {
|
||||
beginTransmission(address);
|
||||
// command byte for reading the data
|
||||
write(0x41);
|
||||
byte[] in = read(2);
|
||||
endTransmission();
|
||||
// put bytes together to tenth of degrees
|
||||
// & 0xff makes sure the byte is not interpreted as a negative value
|
||||
int deg = (in[0] & 0xff) << 8 | (in[1] & 0xff);
|
||||
// return degrees
|
||||
return deg / 10.0;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 194 KiB |
@@ -0,0 +1,12 @@
|
||||
import processing.io.*;
|
||||
MCP4725 dac;
|
||||
|
||||
void setup() {
|
||||
//printArray(I2C.list());
|
||||
dac = new MCP4725(I2C.list()[0], 0x60);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(map(mouseX, 0, width, 0, 255));
|
||||
dac.setAnalog(map(mouseX, 0, width, 0.0, 1.0));
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// MCP4725 is a Digital-to-Analog converter using I2C
|
||||
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf
|
||||
|
||||
class MCP4725 extends I2C {
|
||||
int address;
|
||||
|
||||
// there can be more than one device connected to the bus
|
||||
// as long as they have different addresses
|
||||
MCP4725(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
// outputs voltages from 0V to the supply voltage
|
||||
// (works with 3.3V and 5V)
|
||||
void setAnalog(float fac) {
|
||||
fac = constrain(fac, 0.0, 1.0);
|
||||
// convert to 12 bit value
|
||||
int val = int(4095 * fac);
|
||||
beginTransmission(address);
|
||||
write(val >> 8);
|
||||
write(val & 255);
|
||||
endTransmission();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import processing.io.*;
|
||||
|
||||
// 0.96" 128x64 OLED display ("SKU 346540")
|
||||
SSD1306 oled;
|
||||
|
||||
void setup() {
|
||||
size(128, 64);
|
||||
|
||||
// the display can be set to one of these two addresses: 0x3c (default) or 0x3d
|
||||
// (they might be listed as 0x7a and 0x7b on the circuit board)
|
||||
|
||||
// you might need to use a different interface on other SBCs
|
||||
oled = new SSD1306("i2c-1", 0x3c);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
stroke(255);
|
||||
line(0, 0, 127, 63);
|
||||
line(0, 63, 127, 0);
|
||||
oled.sendImage(get());
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// SSD1306 is a small, inexpensive 128x64 pixels monochrome OLED display
|
||||
// available online as "0.96" 128x64 OLED display", SKU 346540
|
||||
// or from Adafruit
|
||||
// datasheet: https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
|
||||
class SSD1306 extends I2C {
|
||||
int address;
|
||||
|
||||
// there can be more than one device connected to the bus
|
||||
// as long as they have different addresses
|
||||
SSD1306(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
writeCommand(0xae); // turn display off
|
||||
writeCommand(0xa8, 0x3f); // set multiplex ratio to the highest setting
|
||||
writeCommand(0x8d, 0x14); // enable charge pump
|
||||
writeCommand(0x20, 0x00); // set memory addressing mode to horizontal
|
||||
writeCommand(0xd5, 0x80); // set display clock divide ratio & oscillator frequency to default
|
||||
writeCommand(0xd3, 0x00); // no display offset
|
||||
writeCommand(0x40 | 0x00); // set default display start line
|
||||
|
||||
// use the following two lines to flip the display
|
||||
writeCommand(0xa0 | 0x01); // set segment re-map
|
||||
writeCommand(0xc8); // set COM output scan direction
|
||||
|
||||
writeCommand(0xda, 0x12); // set COM pins hardware configuration
|
||||
writeCommand(0xd9, 0xf1); // set pre-charge period to 241x DCLK
|
||||
writeCommand(0xdB, 0x40); // set VCOMH deselect level
|
||||
writeCommand(0xa4); // display RAM content (not all-on)
|
||||
writeCommand(0xa6); // set normal (not-inverted) display
|
||||
|
||||
// set this since we don't have access to the OLED's reset pins (?)
|
||||
writeCommand(0x21, 0, 127); // set column address
|
||||
writeCommand(0x22, 0, 7); // set page address
|
||||
|
||||
writeCommand(0x81, 0xcf); // set contrast
|
||||
writeCommand(0x2e); // deactivate scroll
|
||||
writeCommand(0xaf); // turn display on
|
||||
}
|
||||
|
||||
void invert(boolean inverted) {
|
||||
if (inverted) {
|
||||
writeCommand(0xa7);
|
||||
} else {
|
||||
writeCommand(0xa6);
|
||||
}
|
||||
}
|
||||
|
||||
void sendImage(PImage img) {
|
||||
sendImage(img, 0, 0);
|
||||
}
|
||||
|
||||
void sendImage(PImage img, int startX, int startY) {
|
||||
byte[] frame = new byte[1024];
|
||||
img.loadPixels();
|
||||
for (int y=startY; y < height && y-startY < 64; y++) {
|
||||
for (int x=startX; x < width && x-startX < 128; x++) {
|
||||
if (128 <= brightness(img.pixels[y*img.width+x])) {
|
||||
// this isn't the normal (scanline) mapping, but 8 pixels below each other at a time
|
||||
// white pixels have their bit turned on
|
||||
frame[x + (y/8)*128] |= (1 << (y % 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
sendFramebuffer(frame);
|
||||
}
|
||||
|
||||
void sendFramebuffer(byte[] buf) {
|
||||
if (buf.length != 1024) {
|
||||
System.err.println("The framebuffer should be 1024 bytes long, with one bit per pixel");
|
||||
throw new IllegalArgumentException("Unexpected buffer size");
|
||||
}
|
||||
|
||||
writeCommand(0x00 | 0x0); // set start address
|
||||
writeCommand(0x10 | 0x0); // set higher column start address
|
||||
writeCommand(0x40 | 0x0); // set start line
|
||||
|
||||
// send the frame buffer as 16 byte long packets
|
||||
for (int i=0; i < buf.length/16; i++) {
|
||||
super.beginTransmission(address);
|
||||
super.write(0x40); // indicates data write
|
||||
for (int j=0; j < 16; j++) {
|
||||
super.write(buf[i*16+j]);
|
||||
}
|
||||
super.endTransmission();
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeCommand(int arg1) {
|
||||
super.beginTransmission(address);
|
||||
super.write(0x00); // indicates command write
|
||||
super.write(arg1);
|
||||
super.endTransmission();
|
||||
}
|
||||
|
||||
protected void writeCommand(int arg1, int arg2) {
|
||||
super.beginTransmission(address);
|
||||
super.write(0x00);
|
||||
super.write(arg1);
|
||||
super.write(arg2);
|
||||
super.endTransmission();
|
||||
}
|
||||
|
||||
protected void writeCommand(int arg1, int arg2, int arg3) {
|
||||
super.beginTransmission(address);
|
||||
super.write(0x00);
|
||||
super.write(arg1);
|
||||
super.write(arg2);
|
||||
super.write(arg3);
|
||||
super.endTransmission();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// BME280 is an integrated environmental sensor
|
||||
// It can measure temperature, pressure and humidity
|
||||
// datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
|
||||
// code contributed by @OlivierLD
|
||||
|
||||
public class BME280 extends I2C {
|
||||
|
||||
public final static int BME280_I2CADDR = 0x77; // this is the default I2C address
|
||||
public final static int DEFAULT_ADDR = BME280_I2CADDR;
|
||||
|
||||
// Operating Modes
|
||||
public final static int BME280_OSAMPLE_1 = 1;
|
||||
public final static int BME280_OSAMPLE_2 = 2;
|
||||
public final static int BME280_OSAMPLE_4 = 3;
|
||||
public final static int BME280_OSAMPLE_8 = 4;
|
||||
public final static int BME280_OSAMPLE_16 = 5;
|
||||
|
||||
// BME280 Registers
|
||||
public final static int BME280_REGISTER_DIG_T1 = 0x88; // Trimming parameter registers
|
||||
public final static int BME280_REGISTER_DIG_T2 = 0x8A;
|
||||
public final static int BME280_REGISTER_DIG_T3 = 0x8C;
|
||||
|
||||
public final static int BME280_REGISTER_DIG_P1 = 0x8E;
|
||||
public final static int BME280_REGISTER_DIG_P2 = 0x90;
|
||||
public final static int BME280_REGISTER_DIG_P3 = 0x92;
|
||||
public final static int BME280_REGISTER_DIG_P4 = 0x94;
|
||||
public final static int BME280_REGISTER_DIG_P5 = 0x96;
|
||||
public final static int BME280_REGISTER_DIG_P6 = 0x98;
|
||||
public final static int BME280_REGISTER_DIG_P7 = 0x9A;
|
||||
public final static int BME280_REGISTER_DIG_P8 = 0x9C;
|
||||
public final static int BME280_REGISTER_DIG_P9 = 0x9E;
|
||||
|
||||
public final static int BME280_REGISTER_DIG_H1 = 0xA1;
|
||||
public final static int BME280_REGISTER_DIG_H2 = 0xE1;
|
||||
public final static int BME280_REGISTER_DIG_H3 = 0xE3;
|
||||
public final static int BME280_REGISTER_DIG_H4 = 0xE4;
|
||||
public final static int BME280_REGISTER_DIG_H5 = 0xE5;
|
||||
public final static int BME280_REGISTER_DIG_H6 = 0xE6;
|
||||
public final static int BME280_REGISTER_DIG_H7 = 0xE7;
|
||||
|
||||
public final static int BME280_REGISTER_CHIPID = 0xD0;
|
||||
public final static int BME280_REGISTER_VERSION = 0xD1;
|
||||
public final static int BME280_REGISTER_SOFTRESET = 0xE0;
|
||||
|
||||
public final static int BME280_REGISTER_CONTROL_HUM = 0xF2;
|
||||
public final static int BME280_REGISTER_CONTROL = 0xF4;
|
||||
public final static int BME280_REGISTER_CONFIG = 0xF5;
|
||||
public final static int BME280_REGISTER_PRESSURE_DATA = 0xF7;
|
||||
public final static int BME280_REGISTER_TEMP_DATA = 0xFA;
|
||||
public final static int BME280_REGISTER_HUMIDITY_DATA = 0xFD;
|
||||
|
||||
private int dig_T1 = 0;
|
||||
private int dig_T2 = 0;
|
||||
private int dig_T3 = 0;
|
||||
|
||||
private int dig_P1 = 0;
|
||||
private int dig_P2 = 0;
|
||||
private int dig_P3 = 0;
|
||||
private int dig_P4 = 0;
|
||||
private int dig_P5 = 0;
|
||||
private int dig_P6 = 0;
|
||||
private int dig_P7 = 0;
|
||||
private int dig_P8 = 0;
|
||||
private int dig_P9 = 0;
|
||||
|
||||
private int dig_H1 = 0;
|
||||
private int dig_H2 = 0;
|
||||
private int dig_H3 = 0;
|
||||
private int dig_H4 = 0;
|
||||
private int dig_H5 = 0;
|
||||
private int dig_H6 = 0;
|
||||
|
||||
private float tFine = 0.0f;
|
||||
|
||||
private int address;
|
||||
private int mode = BME280_OSAMPLE_8;
|
||||
private float standardSeaLevelPressure = 101325.0f; // in Pa (1013.25 hPa)
|
||||
|
||||
protected float temp = 0.0f; // most recent sensor readings, set by update()
|
||||
protected float press = 0.0f;
|
||||
protected float hum = 0.0f;
|
||||
|
||||
|
||||
public BME280(String dev) {
|
||||
this(dev, DEFAULT_ADDR);
|
||||
}
|
||||
|
||||
public BME280(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
|
||||
// Soft reset
|
||||
command(BME280_REGISTER_SOFTRESET, (byte)0xB6);
|
||||
// Wait for the chip to wake up
|
||||
delay(300);
|
||||
|
||||
try {
|
||||
readCalibrationData();
|
||||
// showCalibrationData();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
command(BME280_REGISTER_CONTROL, (byte)0x3F);
|
||||
tFine = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read and update all sensors values
|
||||
*/
|
||||
public void update() {
|
||||
// The order used to read the data is important!
|
||||
// 1.temperature, 2.pressure (analog to altitude), 3.humidity.
|
||||
|
||||
try {
|
||||
temp = readTemperature();
|
||||
} catch (Exception ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
press = readPressure();
|
||||
} catch (Exception ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
hum = readHumidity();
|
||||
} catch (Exception ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the temperature in degrees celsius
|
||||
*/
|
||||
public float temperature() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pressure in Pa
|
||||
*/
|
||||
public float pressure() {
|
||||
return press;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude in meters
|
||||
* @param pressure as returned by pressure()
|
||||
*/
|
||||
public float altitude(float pressure) {
|
||||
double altitude = 0.0;
|
||||
if (standardSeaLevelPressure != 0) {
|
||||
altitude = 44330.0 * (1.0 - Math.pow(pressure / standardSeaLevelPressure, 0.1903));
|
||||
}
|
||||
return (float)altitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude in meters
|
||||
* @param pressure as returned by pressure() in Pa
|
||||
* @param temperature as returned by temperature() in Celcius
|
||||
*/
|
||||
public float altitude(float pressure, float temperature) {
|
||||
double altitude = 0.0;
|
||||
if (standardSeaLevelPressure != 0) {
|
||||
altitude = ((Math.pow(standardSeaLevelPressure / pressure, 1 / 5.257) - 1) * (temperature + 273.25)) / 0.0065;
|
||||
}
|
||||
return (float)altitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the humidity in percent
|
||||
*/
|
||||
public float humidity() {
|
||||
return hum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the standard sea level pressure used for calculating altitude()
|
||||
* Defaults to 101325 Pa (1013.25 hPa)
|
||||
*/
|
||||
public void setStandardSeaLevelPressure(float pressure) {
|
||||
standardSeaLevelPressure = pressure;
|
||||
}
|
||||
|
||||
|
||||
protected float readTemperature() {
|
||||
// Returns the compensated temperature in degrees celcius
|
||||
float UT = readRawTemp();
|
||||
float var1 = 0.0f;
|
||||
float var2 = 0.0f;
|
||||
float temp = 0.0f;
|
||||
|
||||
// Read raw temp before aligning it with the calibration values
|
||||
var1 = (UT / 16384.0f - dig_T1 / 1024.0f) * (float) dig_T2;
|
||||
var2 = ((UT / 131072.0f - dig_T1 / 8192.0f) * (UT / 131072.0f - dig_T1 / 8192.0f)) * (float) dig_T3;
|
||||
tFine = (int) (var1 + var2);
|
||||
temp = (var1 + var2) / 5120.0f;
|
||||
// println("DBG: Calibrated temperature = " + temp + " C");
|
||||
return temp;
|
||||
}
|
||||
|
||||
protected float readPressure() {
|
||||
// Returns the compensated pressure in Pascal
|
||||
int adc = readRawPressure();
|
||||
// println("ADC:" + adc + ", tFine:" + tFine);
|
||||
float var1 = (tFine / 2.0f) - 64000.0f;
|
||||
float var2 = var1 * var1 * (dig_P6 / 32768.0f);
|
||||
var2 = var2 + var1 * dig_P5 * 2.0f;
|
||||
var2 = (var2 / 4.0f) + (dig_P4 * 65536.0f);
|
||||
var1 = (dig_P3 * var1 * var1 / 524288.0f + dig_P2 * var1) / 524288.0f;
|
||||
var1 = (1.0f + var1 / 32768.0f) * dig_P1;
|
||||
if (var1 == 0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
float p = 1048576.0f - adc;
|
||||
p = ((p - var2 / 4096.0f) * 6250.0f) / var1;
|
||||
var1 = dig_P9 * p * p / 2147483648.0f;
|
||||
var2 = p * dig_P8 / 32768.0f;
|
||||
p = p + (var1 + var2 + dig_P7) / 16.0f;
|
||||
// println("DBG: Pressure = " + p + " Pa");
|
||||
return p;
|
||||
}
|
||||
|
||||
protected float readHumidity() {
|
||||
// Returns the compensated humidity in percent
|
||||
int adc = readRawHumidity();
|
||||
float h = tFine - 76800.0f;
|
||||
h = (adc - (dig_H4 * 64.0f + dig_H5 / 16384.8f * h)) *
|
||||
(dig_H2 / 65536.0f * (1.0f + dig_H6 / 67108864.0f * h * (1.0f + dig_H3 / 67108864.0f * h)));
|
||||
h = h * (1.0f - dig_H1 * h / 524288.0f);
|
||||
if (h > 100) {
|
||||
h = 100;
|
||||
} else if (h < 0) {
|
||||
h = 0;
|
||||
}
|
||||
// println("DBG: Humidity = " + h);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
private void readCalibrationData() {
|
||||
// Reads the calibration data from the IC
|
||||
dig_T1 = readU16LE(BME280_REGISTER_DIG_T1);
|
||||
dig_T2 = readS16LE(BME280_REGISTER_DIG_T2);
|
||||
dig_T3 = readS16LE(BME280_REGISTER_DIG_T3);
|
||||
|
||||
dig_P1 = readU16LE(BME280_REGISTER_DIG_P1);
|
||||
dig_P2 = readS16LE(BME280_REGISTER_DIG_P2);
|
||||
dig_P3 = readS16LE(BME280_REGISTER_DIG_P3);
|
||||
dig_P4 = readS16LE(BME280_REGISTER_DIG_P4);
|
||||
dig_P5 = readS16LE(BME280_REGISTER_DIG_P5);
|
||||
dig_P6 = readS16LE(BME280_REGISTER_DIG_P6);
|
||||
dig_P7 = readS16LE(BME280_REGISTER_DIG_P7);
|
||||
dig_P8 = readS16LE(BME280_REGISTER_DIG_P8);
|
||||
dig_P9 = readS16LE(BME280_REGISTER_DIG_P9);
|
||||
|
||||
dig_H1 = readU8(BME280_REGISTER_DIG_H1);
|
||||
dig_H2 = readS16LE(BME280_REGISTER_DIG_H2);
|
||||
dig_H3 = readU8(BME280_REGISTER_DIG_H3);
|
||||
dig_H6 = readS8(BME280_REGISTER_DIG_H7);
|
||||
|
||||
int h4 = readS8(BME280_REGISTER_DIG_H4);
|
||||
h4 = (h4 << 24) >> 20;
|
||||
dig_H4 = h4 | (readU8(BME280_REGISTER_DIG_H5) & 0x0F);
|
||||
|
||||
int h5 = readS8(BME280_REGISTER_DIG_H6);
|
||||
h5 = (h5 << 24) >> 20;
|
||||
dig_H5 = h5 | (readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F);
|
||||
}
|
||||
|
||||
private String displayRegister(int reg) {
|
||||
return String.format("0x%s (%d)", lpad(Integer.toHexString(reg & 0xFFFF).toUpperCase(), 4, "0"), reg);
|
||||
}
|
||||
|
||||
private void showCalibrationData() {
|
||||
// Displays the calibration values for debugging purposes
|
||||
println("======================");
|
||||
println("DBG: T1 = " + displayRegister(dig_T1));
|
||||
println("DBG: T2 = " + displayRegister(dig_T2));
|
||||
println("DBG: T3 = " + displayRegister(dig_T3));
|
||||
println("----------------------");
|
||||
println("DBG: P1 = " + displayRegister(dig_P1));
|
||||
println("DBG: P2 = " + displayRegister(dig_P2));
|
||||
println("DBG: P3 = " + displayRegister(dig_P3));
|
||||
println("DBG: P4 = " + displayRegister(dig_P4));
|
||||
println("DBG: P5 = " + displayRegister(dig_P5));
|
||||
println("DBG: P6 = " + displayRegister(dig_P6));
|
||||
println("DBG: P7 = " + displayRegister(dig_P7));
|
||||
println("DBG: P8 = " + displayRegister(dig_P8));
|
||||
println("DBG: P9 = " + displayRegister(dig_P9));
|
||||
println("----------------------");
|
||||
println("DBG: H1 = " + displayRegister(dig_H1));
|
||||
println("DBG: H2 = " + displayRegister(dig_H2));
|
||||
println("DBG: H3 = " + displayRegister(dig_H3));
|
||||
println("DBG: H4 = " + displayRegister(dig_H4));
|
||||
println("DBG: H5 = " + displayRegister(dig_H5));
|
||||
println("DBG: H6 = " + displayRegister(dig_H6));
|
||||
println("======================");
|
||||
}
|
||||
|
||||
private void command(int reg, byte val) {
|
||||
super.beginTransmission(address);
|
||||
super.write(reg);
|
||||
super.write(val);
|
||||
super.endTransmission();
|
||||
}
|
||||
|
||||
private int readRawTemp() {
|
||||
// Returns the raw (uncompensated) temperature
|
||||
int meas = mode;
|
||||
// println(String.format("readRawTemp: 1 - meas=%d", meas));
|
||||
command(BME280_REGISTER_CONTROL_HUM, (byte) meas); // HUM ?
|
||||
meas = mode << 5 | mode << 2 | 1;
|
||||
// println(String.format("readRawTemp: 2 - meas=%d", meas));
|
||||
command(BME280_REGISTER_CONTROL, (byte) meas);
|
||||
|
||||
double sleepTime = 0.00125 + 0.0023 * (1 << mode);
|
||||
sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575;
|
||||
sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575;
|
||||
delay((int)Math.round(sleepTime * 1000));
|
||||
int msb = readU8(BME280_REGISTER_TEMP_DATA);
|
||||
int lsb = readU8(BME280_REGISTER_TEMP_DATA + 1);
|
||||
int xlsb = readU8(BME280_REGISTER_TEMP_DATA + 2);
|
||||
int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4;
|
||||
// println("DBG: Raw Temp: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb));
|
||||
return raw;
|
||||
}
|
||||
|
||||
private int readRawPressure() {
|
||||
// Returns the raw (uncompensated) pressure
|
||||
int msb = readU8(BME280_REGISTER_PRESSURE_DATA);
|
||||
int lsb = readU8(BME280_REGISTER_PRESSURE_DATA + 1);
|
||||
int xlsb = readU8(BME280_REGISTER_PRESSURE_DATA + 2);
|
||||
int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4;
|
||||
// println("DBG: Raw Press: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb));
|
||||
return raw;
|
||||
}
|
||||
|
||||
private int readRawHumidity() {
|
||||
// Returns the raw (uncompensated) humidity
|
||||
int msb = readU8(BME280_REGISTER_HUMIDITY_DATA);
|
||||
int lsb = readU8(BME280_REGISTER_HUMIDITY_DATA + 1);
|
||||
int raw = (msb << 8) | lsb;
|
||||
return raw;
|
||||
}
|
||||
|
||||
private int readU16LE(int register) {
|
||||
super.beginTransmission(address);
|
||||
super.write((byte)register);
|
||||
byte[] ba = super.read(2);
|
||||
super.endTransmission();
|
||||
return ((ba[1] & 0xFF) << 8) + (ba[0] & 0xFF); // Little Endian
|
||||
}
|
||||
|
||||
private int readS16LE(int register) {
|
||||
super.beginTransmission(address);
|
||||
super.write((byte)register);
|
||||
byte[] ba = super.read(2);
|
||||
super.endTransmission();
|
||||
|
||||
int lo = ba[0] & 0xFF;
|
||||
int hi = ba[1] & 0xFF;
|
||||
if (hi > 127)
|
||||
hi -= 256;
|
||||
return (hi << 8) + lo; // Little Endian
|
||||
}
|
||||
|
||||
private int readU8(int register) {
|
||||
super.beginTransmission(address);
|
||||
super.write(register);
|
||||
byte[] ba = super.read(1);
|
||||
super.endTransmission();
|
||||
return (int)(ba[0] & 0xFF);
|
||||
}
|
||||
|
||||
private int readS8(int register) {
|
||||
int val = readU8(register);
|
||||
if (val > 127)
|
||||
val -= 256;
|
||||
return val;
|
||||
}
|
||||
|
||||
private String rpad(String s, int len, String pad) {
|
||||
String str = s;
|
||||
while (str.length() < len) {
|
||||
str += pad;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private String lpad(String s, int len, String pad) {
|
||||
String str = s;
|
||||
while (str.length() < len) {
|
||||
str = pad + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import processing.io.*;
|
||||
BME280 bme280;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
size(720, 320);
|
||||
textSize(72);
|
||||
|
||||
//printArray(I2C.list());
|
||||
bme280 = new BME280("i2c-1", 0x77);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
stroke(255);
|
||||
|
||||
bme280.update();
|
||||
float temp = bme280.temperature();
|
||||
float hum = bme280.humidity();
|
||||
float press = bme280.pressure();
|
||||
text(String.format("Temp: %.02f\272C", temp), 10, 75);
|
||||
text(String.format("Hum: %.02f %%", hum), 10, 150);
|
||||
text(String.format("Press: %.02f hPa", press / 100f), 10, 225);
|
||||
|
||||
// pressure can be used to calculate the altitude like so
|
||||
float alt = bme280.altitude(press, temp);
|
||||
text(String.format("Alt: %.02f m", alt), 10, 300);
|
||||
}
|
||||
|
After Width: | Height: | Size: 227 KiB |
@@ -0,0 +1,25 @@
|
||||
import processing.io.*;
|
||||
color bgcolor = 0;
|
||||
|
||||
// GPIO numbers refer to different phyiscal pins on various boards
|
||||
// On the Raspberry Pi GPIO 4 is physical pin 7 on the header
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
GPIO.pinMode(4, GPIO.INPUT);
|
||||
GPIO.attachInterrupt(4, this, "pinEvent", GPIO.RISING);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(bgcolor);
|
||||
}
|
||||
|
||||
// this function will be called whenever GPIO 4 is brought from LOW to HIGH
|
||||
void pinEvent(int pin) {
|
||||
println("Received interrupt");
|
||||
if (bgcolor == 0) {
|
||||
bgcolor = color(255);
|
||||
} else {
|
||||
bgcolor = color(0);
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 193 KiB |
@@ -0,0 +1,39 @@
|
||||
import processing.io.*;
|
||||
LED leds[];
|
||||
|
||||
// the Raspberry Pi has two build-in LEDs we can control
|
||||
// led0 (green) and led1 (red)
|
||||
|
||||
void setup() {
|
||||
String available[] = LED.list();
|
||||
print("Available: ");
|
||||
println(available);
|
||||
|
||||
// create an object for each LED and store it in an array
|
||||
leds = new LED[available.length];
|
||||
for (int i=0; i < available.length; i++) {
|
||||
leds[i] = new LED(available[i]);
|
||||
}
|
||||
|
||||
frameRate(1);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// make the LEDs count in binary
|
||||
for (int i=0; i < leds.length; i++) {
|
||||
if ((frameCount & (1 << i)) != 0) {
|
||||
leds[i].brightness(1.0);
|
||||
} else {
|
||||
leds[i].brightness(0.0);
|
||||
}
|
||||
}
|
||||
println(frameCount);
|
||||
}
|
||||
|
||||
void keyPressed() {
|
||||
// cleanup
|
||||
for (int i=0; i < leds.length; i++) {
|
||||
leds[i].close();
|
||||
}
|
||||
exit();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import processing.io.*;
|
||||
TSL2561 sensor;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
// this variable will contain the measured brightness
|
||||
// Lux (lx) is the unit of illuminance
|
||||
float lux;
|
||||
|
||||
void setup() {
|
||||
size(700, 100);
|
||||
textSize(72);
|
||||
//printArray(I2C.list());
|
||||
sensor = new TSL2561("i2c-1", 0x39);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
stroke(255);
|
||||
lux = sensor.lux();
|
||||
text(String.format("Light: %.02f Lux", lux), 10, 75);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
// turn the sensor off
|
||||
sensor.stop();
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// TSL2561 is light sensor using I2C
|
||||
// datasheet: https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf
|
||||
// code contributed by @OlivierLD
|
||||
|
||||
public class TSL2561 extends I2C {
|
||||
|
||||
public final static int TSL2561_ADDRESS = 0x39;
|
||||
|
||||
public final static int TSL2561_ADDRESS_LOW = 0x29;
|
||||
public final static int TSL2561_ADDRESS_FLOAT = 0x39;
|
||||
public final static int TSL2561_ADDRESS_HIGH = 0x49;
|
||||
|
||||
public final static int TSL2561_COMMAND_BIT = 0x80;
|
||||
public final static int TSL2561_WORD_BIT = 0x20;
|
||||
public final static int TSL2561_CONTROL_POWERON = 0x03;
|
||||
public final static int TSL2561_CONTROL_POWEROFF = 0x00;
|
||||
|
||||
public final static int TSL2561_REGISTER_CONTROL = 0x00;
|
||||
public final static int TSL2561_REGISTER_TIMING = 0x01;
|
||||
public final static int TSL2561_REGISTER_CHAN0_LOW = 0x0C;
|
||||
public final static int TSL2561_REGISTER_CHAN0_HIGH = 0x0D;
|
||||
public final static int TSL2561_REGISTER_CHAN1_LOW = 0x0E;
|
||||
public final static int TSL2561_REGISTER_CHAN1_HIGH = 0x0F;
|
||||
public final static int TSL2561_REGISTER_ID = 0x0A;
|
||||
|
||||
public final static int TSL2561_GAIN_1X = 0x00;
|
||||
public final static int TSL2561_GAIN_16X = 0x10;
|
||||
|
||||
public final static int TSL2561_INTEGRATIONTIME_13MS = 0x00; // rather 13.7ms
|
||||
public final static int TSL2561_INTEGRATIONTIME_101MS = 0x01;
|
||||
public final static int TSL2561_INTEGRATIONTIME_402MS = 0x02;
|
||||
|
||||
public final static double TSL2561_LUX_K1C = 0.130; // (0x0043) // 0.130 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B1C = 0.0315; // (0x0204) // 0.0315 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M1C = 0.0262; // (0x01ad) // 0.0262 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K2C = 0.260; // (0x0085) // 0.260 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B2C = 0.0337; // (0x0228) // 0.0337 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M2C = 0.0430; // (0x02c1) // 0.0430 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K3C = 0.390; // (0x00c8) // 0.390 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B3C = 0.0363; // (0x0253) // 0.0363 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M3C = 0.0529; // (0x0363) // 0.0529 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K4C = 0.520; // (0x010a) // 0.520 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B4C = 0.0392; // (0x0282) // 0.0392 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M4C = 0.0605; // (0x03df) // 0.0605 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K5C = 0.65; // (0x014d) // 0.65 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B5C = 0.0229; // (0x0177) // 0.0229 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M5C = 0.0291; // (0x01dd) // 0.0291 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K6C = 0.80; // (0x019a) // 0.80 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B6C = 0.0157; // (0x0101) // 0.0157 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M6C = 0.0180; // (0x0127) // 0.0180 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K7C = 1.3; // (0x029a) // 1.3 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B7C = 0.00338; // (0x0037) // 0.00338 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M7C = 0.00260; // (0x002b) // 0.00260 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_K8C = 1.3; // (0x029a) // 1.3 * 2^RATIO_SCALE
|
||||
public final static double TSL2561_LUX_B8C = 0.000; // (0x0000) // 0.000 * 2^LUX_SCALE
|
||||
public final static double TSL2561_LUX_M8C = 0.000; // (0x0000) // 0.000 * 2^LUX_SCALE
|
||||
|
||||
private int gain = TSL2561_GAIN_1X;
|
||||
private int integration = TSL2561_INTEGRATIONTIME_402MS;
|
||||
private int pause = 800;
|
||||
|
||||
private int address;
|
||||
|
||||
|
||||
public TSL2561(String dev) {
|
||||
this(dev, TSL2561_ADDRESS);
|
||||
}
|
||||
|
||||
public TSL2561(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
start();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWERON);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWEROFF);
|
||||
}
|
||||
|
||||
public void setGain() {
|
||||
setGain(TSL2561_GAIN_1X);
|
||||
}
|
||||
|
||||
public void setGain(int gain) {
|
||||
setGain(gain, TSL2561_INTEGRATIONTIME_402MS);
|
||||
}
|
||||
|
||||
public void setGain(int gain, int integration) {
|
||||
if (gain != TSL2561_GAIN_1X && gain != TSL2561_GAIN_16X) {
|
||||
throw new IllegalArgumentException("Invalid gain value");
|
||||
}
|
||||
if (gain != this.gain || integration != this.integration) {
|
||||
command(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, (byte) (gain | integration));
|
||||
//println("Setting low gain");
|
||||
this.gain = gain;
|
||||
this.integration = integration;
|
||||
delay(pause); // pause for integration (pause must be bigger than integration time)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read visible+IR diode from the I2C device
|
||||
*/
|
||||
public int readFull() {
|
||||
int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN0_LOW;
|
||||
return readU16(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read IR only diode from the I2C device
|
||||
*/
|
||||
public int readIR() {
|
||||
int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN1_LOW;
|
||||
return readU16(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Device lux range 0.1 - 40,000+
|
||||
* see https://learn.adafruit.com/tsl2561/overview
|
||||
*/
|
||||
public float lux() {
|
||||
int ambient = this.readFull();
|
||||
int ir = this.readIR();
|
||||
|
||||
//println("IR Result: " + ir);
|
||||
//println("Ambient Result: " + ambient);
|
||||
|
||||
if (ambient >= 0xffff || ir >= 0xffff) {
|
||||
throw new RuntimeException("Gain too high, values exceed range");
|
||||
}
|
||||
double ratio = (ir / (float) ambient);
|
||||
|
||||
/*
|
||||
* For the values below, see https://github.com/adafruit/_TSL2561/blob/master/_TSL2561_U.h
|
||||
*/
|
||||
float lux = 0.0f;
|
||||
if ((ratio >= 0) && (ratio <= TSL2561_LUX_K4C)) {
|
||||
lux = (float)((TSL2561_LUX_B1C * ambient) - (0.0593 * ambient * (Math.pow(ratio, 1.4))));
|
||||
} else if (ratio <= TSL2561_LUX_K5C) {
|
||||
lux = (float)((TSL2561_LUX_B5C * ambient) - (TSL2561_LUX_M5C * ir));
|
||||
} else if (ratio <= TSL2561_LUX_K6C) {
|
||||
lux = (float)((TSL2561_LUX_B6C * ambient) - (TSL2561_LUX_M6C * ir));
|
||||
} else if (ratio <= TSL2561_LUX_K7C) {
|
||||
lux = (float)((TSL2561_LUX_B7C * ambient) - (TSL2561_LUX_M7C * ir));
|
||||
} else if (ratio > TSL2561_LUX_K8C) {
|
||||
lux = 0.0f;
|
||||
}
|
||||
return lux;
|
||||
}
|
||||
|
||||
|
||||
private void command(int register, byte value) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
write(value);
|
||||
endTransmission();
|
||||
}
|
||||
|
||||
private int readU8(int register) {
|
||||
beginTransmission(this.address);
|
||||
write(register);
|
||||
byte[] ba = read(1);
|
||||
endTransmission();
|
||||
return (int)(ba[0] & 0xFF);
|
||||
}
|
||||
|
||||
private int readU16(int register) {
|
||||
int lo = readU8(register);
|
||||
int hi = readU8(register + 1);
|
||||
int result = (hi << 8) + lo; // Big Endian
|
||||
//println("(U16) I2C: Device " + toHex(TSL2561_ADDRESS) + " returned " + toHex(result) + " from reg " + toHex(register));
|
||||
return result;
|
||||
}
|
||||
|
||||
private String toHex(int i) {
|
||||
String s = Integer.toString(i, 16).toUpperCase();
|
||||
while (s.length() % 2 != 0) {
|
||||
s = "0" + s;
|
||||
}
|
||||
return "0x" + s;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 224 KiB |
@@ -0,0 +1,148 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// PCA9685 is a 16-channel servo/PWM driver
|
||||
// datasheet: https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf
|
||||
// code contributed by @OlivierLD
|
||||
|
||||
public class PCA9685 extends I2C {
|
||||
public final static int PCA9685_ADDRESS = 0x40;
|
||||
|
||||
// registers used
|
||||
public final static int MODE1 = 0x00;
|
||||
public final static int PRESCALE = 0xFE;
|
||||
public final static int LED0_ON_L = 0x06;
|
||||
public final static int LED0_ON_H = 0x07;
|
||||
public final static int LED0_OFF_L = 0x08;
|
||||
public final static int LED0_OFF_H = 0x09;
|
||||
|
||||
private int address;
|
||||
private int freq = 200; // 200 Hz default frequency (after power-up)
|
||||
private boolean hasFreqSet = false; // whether a different frequency has been set
|
||||
private int minPulses[] = new int[16];
|
||||
private int maxPulses[] = new int[16];
|
||||
|
||||
|
||||
public PCA9685(String dev) {
|
||||
this(dev, PCA9685_ADDRESS);
|
||||
}
|
||||
public PCA9685(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
// reset device
|
||||
command(MODE1, (byte) 0x00);
|
||||
}
|
||||
|
||||
|
||||
public void attach(int channel) {
|
||||
// same as on Arduino
|
||||
attach(channel, 544, 2400);
|
||||
}
|
||||
|
||||
public void attach(int channel, int minPulse, int maxPulse) {
|
||||
if (channel < 0 || 15 < channel) {
|
||||
throw new IllegalArgumentException("Channel must be between 0 and 15");
|
||||
}
|
||||
minPulses[channel] = minPulse;
|
||||
maxPulses[channel] = maxPulse;
|
||||
|
||||
// set the PWM frequency to be the same as on Arduino
|
||||
if (!hasFreqSet) {
|
||||
frequency(50);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int channel, float angle) {
|
||||
if (channel < 0 || 15 < channel) {
|
||||
throw new IllegalArgumentException("Channel must be between 0 and 15");
|
||||
}
|
||||
if (angle < 0 || 180 < angle) {
|
||||
throw new IllegalArgumentException("Angle must be between 0 and 180");
|
||||
}
|
||||
int us = (int)(minPulses[channel] + (angle/180.0) * (maxPulses[channel]-minPulses[channel]));
|
||||
|
||||
double pulseLength = 1000000; // 1s = 1,000,000 us per pulse
|
||||
pulseLength /= freq; // 40..1000 Hz
|
||||
pulseLength /= 4096; // 12 bits of resolution
|
||||
int pulse = us;
|
||||
pulse /= pulseLength;
|
||||
// println(pulseLength + " us per bit, pulse:" + pulse);
|
||||
pwm(channel, 0, pulse);
|
||||
}
|
||||
|
||||
public boolean attached(int channel) {
|
||||
if (channel < 0 || 15 < channel) {
|
||||
return false;
|
||||
}
|
||||
return (maxPulses[channel] != 0) ? true : false;
|
||||
}
|
||||
|
||||
public void detach(int channel) {
|
||||
pwm(channel, 0, 0);
|
||||
minPulses[channel] = 0;
|
||||
maxPulses[channel] = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param freq 40..1000 Hz
|
||||
*/
|
||||
public void frequency(int freq) {
|
||||
this.freq = freq;
|
||||
float preScaleVal = 25000000.0f; // 25MHz
|
||||
preScaleVal /= 4096.0; // 4096: 12-bit
|
||||
preScaleVal /= freq;
|
||||
preScaleVal -= 1.0;
|
||||
// println("Setting PWM frequency to " + freq + " Hz");
|
||||
// println("Estimated pre-scale: " + preScaleVal);
|
||||
double preScale = Math.floor(preScaleVal + 0.5);
|
||||
// println("Final pre-scale: " + preScale);
|
||||
byte oldmode = (byte) readU8(MODE1);
|
||||
byte newmode = (byte) ((oldmode & 0x7F) | 0x10); // sleep
|
||||
command(MODE1, newmode); // go to sleep
|
||||
command(PRESCALE, (byte) (Math.floor(preScale)));
|
||||
command(MODE1, oldmode);
|
||||
delay(5);
|
||||
command(MODE1, (byte) (oldmode | 0x80));
|
||||
hasFreqSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel 0..15
|
||||
* @param on cycle offset to turn output on (0..4095)
|
||||
* @param off cycle offset to turn output off again (0..4095)
|
||||
*/
|
||||
public void pwm(int channel, int on, int off) {
|
||||
if (channel < 0 || 15 < channel) {
|
||||
throw new IllegalArgumentException("Channel must be between 0 and 15");
|
||||
}
|
||||
if (on < 0 || 4095 < on) {
|
||||
throw new IllegalArgumentException("On must be between 0 and 4095");
|
||||
}
|
||||
if (off < 0 || 4095 < off) {
|
||||
throw new IllegalArgumentException("Off must be between 0 and 4095");
|
||||
}
|
||||
if (off < on) {
|
||||
throw new IllegalArgumentException("Off must be greater than On");
|
||||
}
|
||||
command(LED0_ON_L + 4 * channel, (byte) (on & 0xFF));
|
||||
command(LED0_ON_H + 4 * channel, (byte) (on >> 8));
|
||||
command(LED0_OFF_L + 4 * channel, (byte) (off & 0xFF));
|
||||
command(LED0_OFF_H + 4 * channel, (byte) (off >> 8));
|
||||
}
|
||||
|
||||
|
||||
private void command(int register, byte value) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
write(value);
|
||||
endTransmission();
|
||||
}
|
||||
|
||||
private byte readU8(int register) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
byte[] ba = read(1);
|
||||
endTransmission();
|
||||
return (byte)(ba[0] & 0xFF);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import processing.io.*;
|
||||
PCA9685 servos;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
size(400, 300);
|
||||
//printArray(I2C.list());
|
||||
servos = new PCA9685("i2c-1", 0x40);
|
||||
|
||||
// different servo motors will vary in the pulse width they expect
|
||||
// the lines below set the pulse width for 0 degrees to 544 microseconds (μs)
|
||||
// and the pulse width for 180 degrees to 2400 microseconds
|
||||
// these values match the defaults of the Servo library on Arduino
|
||||
// but you might need to modify this for your particular servo still
|
||||
servos.attach(0, 544, 2400);
|
||||
servos.attach(1, 544, 2400);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
stroke(255);
|
||||
strokeWeight(3);
|
||||
|
||||
// we don't go right to the edge to prevent
|
||||
// making the servo unhappy
|
||||
float angle = 90 + sin(frameCount / 100.0)*85;
|
||||
servos.write(0, angle);
|
||||
float y = map(angle, 0, 180, 0, height);
|
||||
line(0, y, width/2, y);
|
||||
|
||||
angle = 90 + cos(frameCount / 100.0)*85;
|
||||
servos.write(1, 90 + cos(frameCount / 100.0)*85);
|
||||
y = map(angle, 0, 180, 0, height);
|
||||
line(width/2, y, width, y);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
servos.detach(0);
|
||||
servos.detach(1);
|
||||
}
|
||||
|
After Width: | Height: | Size: 253 KiB |
@@ -0,0 +1,30 @@
|
||||
import processing.io.*;
|
||||
I2C i2c;
|
||||
|
||||
// MCP4725 is a Digital-to-Analog converter using I2C
|
||||
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf
|
||||
|
||||
// also see DigitalAnalog_I2C_MCP4725 for how to write the
|
||||
// same sketch in an object-oriented way
|
||||
|
||||
void setup() {
|
||||
//printArray(I2C.list());
|
||||
i2c = new I2C(I2C.list()[0]);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(map(mouseX, 0, width, 0, 255));
|
||||
setAnalog(map(mouseX, 0, width, 0.0, 1.0));
|
||||
}
|
||||
|
||||
// outputs voltages from 0V to the supply voltage
|
||||
// (works with 3.3V and 5V)
|
||||
void setAnalog(float fac) {
|
||||
fac = constrain(fac, 0.0, 1.0);
|
||||
// convert to 12 bit value
|
||||
int val = int(4095 * fac);
|
||||
i2c.beginTransmission(0x60);
|
||||
i2c.write(val >> 8);
|
||||
i2c.write(val & 255);
|
||||
i2c.endTransmission();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import processing.io.*;
|
||||
|
||||
// GPIO numbers refer to different phyiscal pins on various boards
|
||||
// On the Raspberry Pi GPIO 4 is physical pin 7 on the header
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
// INPUT_PULLUP enables the built-in pull-up resistor for this pin
|
||||
// left alone, the pin will read as HIGH
|
||||
// connected to ground (via e.g. a button or switch) it will read LOW
|
||||
GPIO.pinMode(4, GPIO.INPUT_PULLUP);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (GPIO.digitalRead(4) == GPIO.LOW) {
|
||||
// button is pressed
|
||||
fill(255);
|
||||
} else {
|
||||
// button is not pressed
|
||||
fill(204);
|
||||
}
|
||||
stroke(255);
|
||||
ellipse(width/2, height/2, width*0.75, height*0.75);
|
||||
}
|
||||
|
After Width: | Height: | Size: 193 KiB |
@@ -0,0 +1,25 @@
|
||||
import processing.io.*;
|
||||
boolean ledOn = false;
|
||||
|
||||
// GPIO numbers refer to different phyiscal pins on various boards
|
||||
// On the Raspberry Pi GPIO 4 is physical pin 7 on the header
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
GPIO.pinMode(4, GPIO.OUTPUT);
|
||||
frameRate(0.5);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// make the LED blink
|
||||
ledOn = !ledOn;
|
||||
if (ledOn) {
|
||||
GPIO.digitalWrite(4, GPIO.LOW);
|
||||
fill(204);
|
||||
} else {
|
||||
GPIO.digitalWrite(4, GPIO.HIGH);
|
||||
fill(255);
|
||||
}
|
||||
stroke(255);
|
||||
ellipse(width/2, height/2, width*0.75, height*0.75);
|
||||
}
|
||||
|
After Width: | Height: | Size: 194 KiB |
@@ -0,0 +1,56 @@
|
||||
import processing.io.*;
|
||||
|
||||
// using a capacitor that gets charged and discharged, while
|
||||
// measuring the time it takes, is an inexpensive way to
|
||||
// read the value of an (analog) resistive sensor, such as
|
||||
// a photocell
|
||||
// kudos to ladyada for the original tutorial
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
int max = 0;
|
||||
int min = 9999;
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void draw() {
|
||||
int val = sensorRead(4);
|
||||
println(val);
|
||||
|
||||
// track largest and smallest reading, to get a sense
|
||||
// how we compare
|
||||
if (max < val) {
|
||||
max = val;
|
||||
}
|
||||
if (val < min) {
|
||||
min = val;
|
||||
}
|
||||
|
||||
// convert current reading into a number between 0.0 and 1.0
|
||||
float frac = map(val, min, max, 0.0, 1.0);
|
||||
|
||||
background(255 * frac);
|
||||
}
|
||||
|
||||
int sensorRead(int pin) {
|
||||
// discharge the capacitor
|
||||
GPIO.pinMode(pin, GPIO.OUTPUT);
|
||||
GPIO.digitalWrite(pin, GPIO.LOW);
|
||||
delay(100);
|
||||
// now the capacitor should be empty
|
||||
|
||||
// measure the time takes to fill it
|
||||
// up to ~ 1.4V again
|
||||
GPIO.pinMode(pin, GPIO.INPUT);
|
||||
int start = millis();
|
||||
while (GPIO.digitalRead(pin) == GPIO.LOW) {
|
||||
// wait
|
||||
}
|
||||
|
||||
// return the time elapsed
|
||||
// this will vary based on the value of the
|
||||
// resistive sensor (lower resistance will
|
||||
// make the capacitor charge faster)
|
||||
return millis() - start;
|
||||
}
|
||||
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,25 @@
|
||||
import processing.io.*;
|
||||
SPI spi;
|
||||
|
||||
// MCP3001 is a Analog-to-Digital converter using SPI
|
||||
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
// also see AnalogDigital_SPI_MCP3001 for how to write the
|
||||
// same sketch in an object-oriented way
|
||||
|
||||
void setup() {
|
||||
//printArray(SPI.list());
|
||||
spi = new SPI(SPI.list()[0]);
|
||||
spi.settings(500000, SPI.MSBFIRST, SPI.MODE0);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// dummy write, actual values don't matter
|
||||
byte[] out = { 0, 0 };
|
||||
byte[] in = spi.transfer(out);
|
||||
// some input bit shifting according to the datasheet p. 16
|
||||
int val = ((in[0] & 0x1f) << 5) | ((in[1] & 0xf8) >> 3);
|
||||
// val is between 0 and 1023
|
||||
background(map(val, 0, 1023, 0, 255));
|
||||
}
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,34 @@
|
||||
import processing.io.*;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
// for more reliable operation it is recommended to power
|
||||
// the servo from an external power source, see setup_better.png
|
||||
|
||||
SoftwareServo servo1;
|
||||
SoftwareServo servo2;
|
||||
|
||||
void setup() {
|
||||
size(400, 300);
|
||||
servo1 = new SoftwareServo(this);
|
||||
servo1.attach(17);
|
||||
servo2 = new SoftwareServo(this);
|
||||
servo2.attach(4);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(0);
|
||||
stroke(255);
|
||||
strokeWeight(3);
|
||||
|
||||
// we don't go right to the edge to prevent
|
||||
// making the servo unhappy
|
||||
float angle = 90 + sin(frameCount / 100.0)*85;
|
||||
servo1.write(angle);
|
||||
float y = map(angle, 0, 180, 0, height);
|
||||
line(0, y, width/2, y);
|
||||
|
||||
angle = 90 + cos(frameCount / 100.0)*85;
|
||||
servo2.write(90 + cos(frameCount / 100.0)*85);
|
||||
y = map(angle, 0, 180, 0, height);
|
||||
line(width/2, y, width, y);
|
||||
}
|
||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1,112 @@
|
||||
import processing.io.I2C;
|
||||
|
||||
// MPR121 is a capacitive-touch sensor controller with 12 channels
|
||||
// datasheet: https://www.nxp.com/docs/en/data-sheet/MPR121.pdf
|
||||
|
||||
class MPR121 extends I2C {
|
||||
int address;
|
||||
int touched;
|
||||
|
||||
// registers used (there are more)
|
||||
static final int EFD0LB = 0x04; // ELE0 Electrode Filtered Data LSB
|
||||
static final int E0TTH = 0x41; // ELE0 Touch Threshold
|
||||
static final int E0RTH = 0x42; // ELE0 Release Threshold
|
||||
static final int E0BV = 0x1e; // ELE0 Baseline Value
|
||||
static final int MHDR = 0x2b; // MHD Rising
|
||||
static final int NHDR = 0x2c; // NHD Amount Rising
|
||||
static final int NCLR = 0x2d; // NCL Rising
|
||||
static final int MHDF = 0x2f; // MHD Falling
|
||||
static final int NHDF = 0x30; // NHD Amount Falling
|
||||
static final int NCLF = 0x31; // NCL Falling
|
||||
static final int CDT = 0x5d; // Filter/Global CDT Configuration
|
||||
static final int ECR = 0x5e; // Electrode Configuration
|
||||
static final int SRST = 0x80; // Soft Reset
|
||||
|
||||
// there can be more than one device connected to the bus
|
||||
// as long as they have different addresses
|
||||
// possible addresses: 0x5a (default) - 0x5d
|
||||
MPR121(String dev, int address) {
|
||||
super(dev);
|
||||
this.address = address;
|
||||
reset();
|
||||
}
|
||||
|
||||
void update() {
|
||||
beginTransmission(address);
|
||||
write(0x00);
|
||||
byte[] in = read(2);
|
||||
// & 0xff makes sure the byte is not interpreted as a negative value
|
||||
touched = (in[1] & 0xff) << 8 | (in[0] & 0xff);
|
||||
}
|
||||
|
||||
boolean touched(int channel) {
|
||||
if (channel < 0 || 11 < channel) {
|
||||
return false;
|
||||
}
|
||||
if ((touched & (1 << channel)) != 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void threshold(int touch, int release) {
|
||||
for (int i=0; i < 12; i++) {
|
||||
threshold(touch, release, i);
|
||||
}
|
||||
}
|
||||
|
||||
void threshold(int touch, int release, int channel) {
|
||||
if (channel < 0 || 11 < channel) {
|
||||
return;
|
||||
}
|
||||
touch = constrain(touch, 0, 255);
|
||||
release = constrain(release, 0, 255);
|
||||
writeRegister(E0TTH + 2*channel, touch);
|
||||
writeRegister(E0RTH + 2*channel, release);
|
||||
}
|
||||
|
||||
int analogRead(int channel) {
|
||||
if (channel < 0 || 11 < channel) {
|
||||
return 0;
|
||||
}
|
||||
beginTransmission(address);
|
||||
write(EFD0LB + 2*channel);
|
||||
byte[] in = read(2);
|
||||
return (in[1] & 0xff) << 8 | (in[0] & 0xff);
|
||||
}
|
||||
|
||||
int analogReadBaseline(int channel) {
|
||||
if (channel < 0 || 11 < channel) {
|
||||
return 0;
|
||||
}
|
||||
beginTransmission(address);
|
||||
write(E0BV + channel);
|
||||
byte[] in = read(1);
|
||||
return (in[0] & 0xff) << 2;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
writeRegister(SRST, 0x63);
|
||||
delay(1);
|
||||
threshold(12, 6);
|
||||
// set baseline filtering control registers (see p. 12)
|
||||
writeRegister(MHDR, 0x01);
|
||||
writeRegister(NHDR, 0x01);
|
||||
writeRegister(NCLR, 0x0e);
|
||||
writeRegister(MHDF, 0x01);
|
||||
writeRegister(NHDF, 0x05);
|
||||
writeRegister(NCLF, 0x01);
|
||||
// change sample interval to 1ms period from default 16ms
|
||||
writeRegister(CDT, 0x20);
|
||||
// start sampling
|
||||
writeRegister(ECR, 0x8f);
|
||||
}
|
||||
|
||||
void writeRegister(int register, int value) {
|
||||
beginTransmission(address);
|
||||
write(register);
|
||||
write(value);
|
||||
endTransmission();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import processing.io.*;
|
||||
MPR121 touch;
|
||||
|
||||
// see setup.png in the sketch folder for wiring details
|
||||
|
||||
void setup() {
|
||||
size(600, 200);
|
||||
//printArray(I2C.list());
|
||||
touch = new MPR121("i2c-1", 0x5a);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(204);
|
||||
noStroke();
|
||||
|
||||
touch.update();
|
||||
|
||||
for (int i=0; i < 12; i++) {
|
||||
if (touch.touched(i)) {
|
||||
fill(255, 0, 0);
|
||||
} else {
|
||||
fill(255, 255, 255);
|
||||
}
|
||||
ellipse((width/12) * (i+0.5), height/2, 20, 20);
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 178 KiB |
@@ -0,0 +1,9 @@
|
||||
name = Hardware I/O
|
||||
authors = The Processing Foundation
|
||||
url = http://processing.org/reference/libraries/io/index.html
|
||||
categories = Hardware
|
||||
sentence = Access peripherals on the Raspberry Pi and other Linux-based computers.
|
||||
paragraph = For other platforms, this is solely provided in order to build and export sketches that require processing.io.
|
||||
version = 1
|
||||
prettyVersion = 1
|
||||
minRevision = 247
|
||||
@@ -0,0 +1 @@
|
||||
name = Hardware I/O for Raspberry Pi and other Linux-based computers
|
||||
@@ -0,0 +1,20 @@
|
||||
TARGET := libprocessing-io.so
|
||||
OBJS := impl.o
|
||||
CC := gcc
|
||||
|
||||
# prefix with -m32 to compile for linux32
|
||||
CFLAGS := -std=gnu99 -fPIC -g -ffast-math
|
||||
CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include
|
||||
CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include/linux
|
||||
LDFLAGS := -shared
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
||||
|
||||
iface.h:
|
||||
javah -classpath .. -o iface.h processing.io.NativeInterface
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
.PHONY: iface.h clean
|
||||
@@ -0,0 +1,133 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class processing_io_NativeInterface */
|
||||
|
||||
#ifndef _Included_processing_io_NativeInterface
|
||||
#define _Included_processing_io_NativeInterface
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: openDevice
|
||||
* Signature: (Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_openDevice
|
||||
(JNIEnv *, jclass, jstring);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: getError
|
||||
* Signature: (I)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_processing_io_NativeInterface_getError
|
||||
(JNIEnv *, jclass, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: closeDevice
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_closeDevice
|
||||
(JNIEnv *, jclass, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: readFile
|
||||
* Signature: (Ljava/lang/String;[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_readFile
|
||||
(JNIEnv *, jclass, jstring, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: writeFile
|
||||
* Signature: (Ljava/lang/String;[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_writeFile
|
||||
(JNIEnv *, jclass, jstring, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: raspbianGpioMemRead
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemRead
|
||||
(JNIEnv *, jclass, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: raspbianGpioMemWrite
|
||||
* Signature: (III)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemWrite
|
||||
(JNIEnv *, jclass, jint, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: raspbianGpioMemWrite
|
||||
* Signature: (II)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemSetPinBias
|
||||
(JNIEnv *, jclass, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: pollDevice
|
||||
* Signature: (Ljava/lang/String;I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_pollDevice
|
||||
(JNIEnv *, jclass, jstring, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: transferI2c
|
||||
* Signature: (II[B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferI2c
|
||||
(JNIEnv *, jclass, jint, jint, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: servoStartThread
|
||||
* Signature: (III)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_processing_io_NativeInterface_servoStartThread
|
||||
(JNIEnv *, jclass, jint, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: servoUpdateThread
|
||||
* Signature: (JII)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoUpdateThread
|
||||
(JNIEnv *, jclass, jlong, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: servoStopThread
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoStopThread
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: setSpiSettings
|
||||
* Signature: (IIII)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_setSpiSettings
|
||||
(JNIEnv *, jclass, jint, jint, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: processing_io_NativeInterface
|
||||
* Method: transferSpi
|
||||
* Signature: (I[B[B)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferSpi
|
||||
(JNIEnv *, jclass, jint, jbyteArray, jbyteArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "iface.h"
|
||||
|
||||
|
||||
static const int servo_pulse_oversleep = 35; // amount of uS to account for when sleeping
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_openDevice
|
||||
(JNIEnv *env, jclass cls, jstring _fn)
|
||||
{
|
||||
const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
|
||||
int file = open(fn, O_RDWR);
|
||||
(*env)->ReleaseStringUTFChars(env, _fn, fn);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
} else {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_processing_io_NativeInterface_getError
|
||||
(JNIEnv *env, jclass cls, jint _errno)
|
||||
{
|
||||
char *msg = strerror(abs(_errno));
|
||||
if (msg) {
|
||||
return (*env)->NewStringUTF(env, msg);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_closeDevice
|
||||
(JNIEnv *env, jclass cls, jint handle)
|
||||
{
|
||||
if (close(handle) < 0) {
|
||||
return -errno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_readFile
|
||||
(JNIEnv *env, jclass cls, jstring _fn, jbyteArray _in)
|
||||
{
|
||||
const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
|
||||
int file = open(fn, O_RDONLY);
|
||||
(*env)->ReleaseStringUTFChars(env, _fn, fn);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
jbyte *in = (*env)->GetByteArrayElements(env, _in, NULL);
|
||||
int len = read(file, in, (*env)->GetArrayLength(env, _in));
|
||||
if (len < 0) {
|
||||
len = -errno;
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements(env, _in, in, 0);
|
||||
|
||||
close(file);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_writeFile
|
||||
(JNIEnv *env, jclass cls, jstring _fn, jbyteArray _out)
|
||||
{
|
||||
const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
|
||||
int file = open(fn, O_WRONLY);
|
||||
(*env)->ReleaseStringUTFChars(env, _fn, fn);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
jbyte *out = (*env)->GetByteArrayElements(env, _out, JNI_FALSE);
|
||||
int len = write(file, out, (*env)->GetArrayLength(env, _out));
|
||||
if (len < 0) {
|
||||
len = -errno;
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);
|
||||
|
||||
close(file);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemRead
|
||||
(JNIEnv *env, jclass cls, jint offset)
|
||||
{
|
||||
// validate offset
|
||||
if (4096 <= offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
uint32_t *mem = mmap(NULL, 4096, PROT_READ, MAP_SHARED, file, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
close(file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
uint32_t value = mem[offset];
|
||||
|
||||
munmap(mem, 4096);
|
||||
close(file);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemWrite
|
||||
(JNIEnv *env, jclass cls, jint offset, jint mask, jint value)
|
||||
{
|
||||
// validate offset
|
||||
if (4096 <= offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
close(file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
mem[offset] = (mem[offset] & ~mask) | (value & mask);
|
||||
|
||||
munmap(mem, 4096);
|
||||
close(file);
|
||||
return 1; // number of bytes written
|
||||
}
|
||||
|
||||
|
||||
#define BCM2835_GPPUD_OFFSET (0x94 >> 2)
|
||||
#define BCM2835_GPPUDCLK0_OFFSET (0x98 >> 2)
|
||||
#define BCM2835_GPPUDCLK1_OFFSET (0x9c >> 2)
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemSetPinBias
|
||||
(JNIEnv *env, jclass cls, jint gpio, jint mode)
|
||||
{
|
||||
int ret = 0; // success
|
||||
|
||||
int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
close(file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// validate arguments
|
||||
if (gpio < 0 || 53 < gpio) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// see BCM2835 datasheet, p. 101
|
||||
uint32_t pud;
|
||||
if (mode == 0) {
|
||||
pud = 0; // floating
|
||||
} else if (mode == 2) {
|
||||
pud = 2; // pull-up
|
||||
} else if (mode == 3) {
|
||||
pud = 1; // pull-down
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* From the BCM2835 datasheet, p. 101:
|
||||
*
|
||||
* The following sequence of events is required:
|
||||
* 1. Write to GPPUD to set the required control signal (i.e. Pull-up or
|
||||
* Pull-Down or neither to remove the current Pull-up/down)
|
||||
* 2. Wait 150 cycles – this provides the required set-up time for the
|
||||
* control signal
|
||||
* 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads
|
||||
* you wish to modify – NOTE only the pads which receive a clock will
|
||||
* be modified, all others will retain their previous state.
|
||||
* 4. Wait 150 cycles – this provides the required hold time for the
|
||||
* control signal
|
||||
* 5. Write to GPPUD to remove the control signal
|
||||
* 6. Write to GPPUDCLK0/1 to remove the clock
|
||||
*/
|
||||
|
||||
// python-gpiozero uses a delay of 214 ns, so we do the same
|
||||
struct timespec wait;
|
||||
wait.tv_sec = 0;
|
||||
wait.tv_nsec = 214;
|
||||
|
||||
mem[BCM2835_GPPUD_OFFSET] = pud;
|
||||
nanosleep(&wait, NULL);
|
||||
if (gpio < 32) {
|
||||
mem[BCM2835_GPPUDCLK0_OFFSET] = 1 << gpio;
|
||||
} else {
|
||||
mem[BCM2835_GPPUDCLK1_OFFSET] = 1 << (gpio-32);
|
||||
}
|
||||
nanosleep(&wait, NULL);
|
||||
mem[BCM2835_GPPUD_OFFSET] = 0;
|
||||
if (gpio < 32) {
|
||||
mem[BCM2835_GPPUDCLK0_OFFSET] = 0;
|
||||
} else {
|
||||
mem[BCM2835_GPPUDCLK1_OFFSET] = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
munmap(mem, 4096);
|
||||
close(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_pollDevice
|
||||
(JNIEnv *env, jclass cls, jstring _fn, jint timeout)
|
||||
{
|
||||
const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
|
||||
int file = open(fn, O_RDONLY|O_NONBLOCK);
|
||||
(*env)->ReleaseStringUTFChars(env, _fn, fn);
|
||||
if (file < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// dummy read
|
||||
char tmp;
|
||||
while (0 < read(file, &tmp, 1));
|
||||
|
||||
struct pollfd fds[1];
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = file;
|
||||
fds[0].events = POLLPRI|POLLERR;
|
||||
|
||||
// and wait
|
||||
int ret = poll(fds, 1, timeout);
|
||||
close(file);
|
||||
|
||||
if (ret < 0) {
|
||||
return -errno;
|
||||
} else if (ret == 0) {
|
||||
// timeout
|
||||
return 0;
|
||||
} else if (fds[0].revents & POLLPRI) {
|
||||
// interrupt
|
||||
return 1;
|
||||
} else {
|
||||
// POLLERR?
|
||||
return -ENOMSG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferI2c
|
||||
(JNIEnv *env, jclass cls, jint handle, jint slave, jbyteArray _out, jbyteArray _in)
|
||||
{
|
||||
struct i2c_rdwr_ioctl_data packets;
|
||||
struct i2c_msg msgs[2];
|
||||
jbyte *out, *in;
|
||||
|
||||
packets.msgs = msgs;
|
||||
packets.nmsgs = 0;
|
||||
|
||||
if (_out != NULL) {
|
||||
msgs[packets.nmsgs].addr = slave;
|
||||
msgs[packets.nmsgs].flags = 0;
|
||||
msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _out);
|
||||
out = (*env)->GetByteArrayElements(env, _out, NULL);
|
||||
msgs[packets.nmsgs].buf = out;
|
||||
packets.nmsgs++;
|
||||
}
|
||||
if (_in != NULL) {
|
||||
msgs[packets.nmsgs].addr = slave;
|
||||
msgs[packets.nmsgs].flags = I2C_M_RD; // I2C_M_RECV_LEN is not supported
|
||||
msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _in);
|
||||
in = (*env)->GetByteArrayElements(env, _in, NULL);
|
||||
msgs[packets.nmsgs].buf = in;
|
||||
packets.nmsgs++;
|
||||
}
|
||||
|
||||
// set the timeout to 100ms - this helps slow devices such as the
|
||||
// Arduino Uno to keep up
|
||||
ioctl(handle, I2C_TIMEOUT, 10);
|
||||
int ret = ioctl(handle, I2C_RDWR, &packets);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
if (_out != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);
|
||||
}
|
||||
if (_in != NULL) {
|
||||
(*env)->ReleaseByteArrayElements(env, _in, in, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
pthread_t thread;
|
||||
int pulse;
|
||||
int period;
|
||||
} SERVO_STATE_T;
|
||||
|
||||
|
||||
static void* servoThread(void *ptr) {
|
||||
SERVO_STATE_T *state = (SERVO_STATE_T*)ptr;
|
||||
struct timespec on, off;
|
||||
on.tv_sec = 0;
|
||||
off.tv_sec = 0;
|
||||
|
||||
do {
|
||||
write(state->fd, "1", 1);
|
||||
|
||||
on.tv_nsec = state->pulse * 1000;
|
||||
nanosleep(&on, NULL);
|
||||
|
||||
write(state->fd, "0", 1);
|
||||
|
||||
off.tv_nsec = (state->period - state->pulse) * 1000;
|
||||
nanosleep(&off, NULL);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_processing_io_NativeInterface_servoStartThread
|
||||
(JNIEnv *env, jclass cls, jint gpio, jint pulse, jint period)
|
||||
{
|
||||
char path[26 + 19 + 1];
|
||||
int fd;
|
||||
pthread_t thread;
|
||||
|
||||
// setup struct holding our state
|
||||
SERVO_STATE_T *state = malloc(sizeof(SERVO_STATE_T));
|
||||
if (!state) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->pulse = (pulse - servo_pulse_oversleep > 0) ? pulse - servo_pulse_oversleep : 0;
|
||||
// we're obviously also oversleeping in the general period case
|
||||
// but other than the pulse, this doesn't seem to be crucial with servos
|
||||
state->period = period;
|
||||
|
||||
// open gpio
|
||||
sprintf(path, "/sys/class/gpio/gpio%d/value", gpio);
|
||||
state->fd = open(path, O_WRONLY);
|
||||
if (state->fd < 0) {
|
||||
free(state);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// start thread
|
||||
int ret = pthread_create(&state->thread, NULL, servoThread, state);
|
||||
if (ret != 0) {
|
||||
free(state);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
// set scheduling policy and priority
|
||||
struct sched_param param;
|
||||
param.sched_priority = 75;
|
||||
ret = pthread_setschedparam(state->thread, SCHED_FIFO, ¶m);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error setting thread policy: %s\n", strerror(ret));
|
||||
}
|
||||
|
||||
return (intptr_t)state;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoUpdateThread
|
||||
(JNIEnv *env, jclass cls, jlong handle, jint pulse, jint period)
|
||||
{
|
||||
SERVO_STATE_T *state = (SERVO_STATE_T*)(intptr_t)handle;
|
||||
state->pulse = (pulse - servo_pulse_oversleep > 0) ? pulse - servo_pulse_oversleep : 0;
|
||||
state->period = period;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoStopThread
|
||||
(JNIEnv *env, jclass cls, jlong handle)
|
||||
{
|
||||
SERVO_STATE_T *state = (SERVO_STATE_T*)(intptr_t)handle;
|
||||
|
||||
// signal thread to stop
|
||||
pthread_cancel(state->thread);
|
||||
pthread_join(state->thread, NULL);
|
||||
|
||||
close(state->fd);
|
||||
free(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_setSpiSettings
|
||||
(JNIEnv *env, jclass cls, jint handle, jint _maxSpeed, jint dataOrder, jint mode)
|
||||
{
|
||||
uint8_t tmp;
|
||||
uint32_t maxSpeed;
|
||||
|
||||
tmp = (uint8_t)mode;
|
||||
int ret = ioctl(handle, SPI_IOC_WR_MODE, &tmp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
tmp = (uint8_t)dataOrder;
|
||||
ret = ioctl(handle, SPI_IOC_WR_LSB_FIRST, &tmp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
maxSpeed = (uint32_t)_maxSpeed;
|
||||
ret = ioctl(handle, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferSpi
|
||||
(JNIEnv *env, jclass cls, jint handle, jbyteArray _out, jbyteArray _in)
|
||||
{
|
||||
jbyte* out = (*env)->GetByteArrayElements(env, _out, NULL);
|
||||
jbyte* in = (*env)->GetByteArrayElements(env, _in, NULL);
|
||||
|
||||
struct spi_ioc_transfer xfer = {
|
||||
.tx_buf = (unsigned long)out,
|
||||
.rx_buf = (unsigned long)in,
|
||||
.len = MIN((*env)->GetArrayLength(env, _out), (*env)->GetArrayLength(env, _in)),
|
||||
};
|
||||
|
||||
int ret = ioctl(handle, SPI_IOC_MESSAGE(1), &xfer);
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, _in, in, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,529 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.core.*;
|
||||
import processing.io.NativeInterface;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class GPIO {
|
||||
|
||||
// those constants are generally the same as in Arduino.h
|
||||
public static final int INPUT = 0;
|
||||
public static final int OUTPUT = 1;
|
||||
public static final int INPUT_PULLUP = 2;
|
||||
public static final int INPUT_PULLDOWN = 3;
|
||||
|
||||
public static final int LOW = 0;
|
||||
public static final int HIGH = 1;
|
||||
|
||||
public static final int NONE = 0;
|
||||
/**
|
||||
* trigger when level changes
|
||||
*/
|
||||
public static final int CHANGE = 1;
|
||||
/**
|
||||
* trigger when level changes from high to low
|
||||
*/
|
||||
public static final int FALLING = 2;
|
||||
/**
|
||||
* trigger when level changes from low to high
|
||||
*/
|
||||
public static final int RISING = 3;
|
||||
|
||||
protected static Map<Integer, Thread> irqThreads = new HashMap<Integer, Thread>();
|
||||
protected static boolean serveInterrupts = true;
|
||||
protected static BitSet values = new BitSet();
|
||||
|
||||
|
||||
static {
|
||||
NativeInterface.loadLibrary();
|
||||
}
|
||||
|
||||
|
||||
public static void analogWrite(int pin, int value) {
|
||||
// currently this can't be done in a non-platform-specific way
|
||||
// the best way forward would be implementing a generic, "soft"
|
||||
// PWM in the kernel that uses high resolution timers, similiar
|
||||
// to the patch Bill Gatliff posted, which unfortunately didn't
|
||||
// get picked up, see
|
||||
// https://dev.openwrt.org/browser/trunk/target/linux/generic/files/drivers/pwm/gpio-pwm.c?rev=35328
|
||||
|
||||
// additionally, there currently doesn't seem to be a way to link
|
||||
// a PWM channel back to the GPIO pin it is associated with
|
||||
|
||||
// alternatively, this could be implemented in user-space to some
|
||||
// degree
|
||||
// see http://stackoverflow.com/a/13371570/3030124
|
||||
// see http://raspberrypi.stackexchange.com/a/304
|
||||
throw new RuntimeException("Not yet implemented");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function when the value of an input pin changes
|
||||
* @param pin GPIO pin
|
||||
* @param parent typically use "this"
|
||||
* @param method name of sketch method to call
|
||||
* @param mode when to call: GPIO.CHANGE, GPIO.FALLING or GPIO.RISING
|
||||
* @see noInterrupts
|
||||
* @see interrupts
|
||||
* @see releaseInterrupt
|
||||
* @webref
|
||||
*/
|
||||
public static void attachInterrupt(int pin, PApplet parent, String method, int mode) {
|
||||
if (irqThreads.containsKey(pin)) {
|
||||
throw new RuntimeException("You must call releaseInterrupt before attaching another interrupt on the same pin");
|
||||
}
|
||||
|
||||
enableInterrupt(pin, mode);
|
||||
|
||||
final int irqPin = pin;
|
||||
final PApplet irqObject = parent;
|
||||
final Method irqMethod;
|
||||
try {
|
||||
irqMethod = parent.getClass().getMethod(method, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Method " + method + " does not exist");
|
||||
}
|
||||
|
||||
// it might be worth checking how Java threads compare to pthreads in terms
|
||||
// of latency
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
boolean gotInterrupt = false;
|
||||
try {
|
||||
do {
|
||||
try {
|
||||
if (waitForInterrupt(irqPin, 100)) {
|
||||
gotInterrupt = true;
|
||||
}
|
||||
if (gotInterrupt && serveInterrupts) {
|
||||
irqMethod.invoke(irqObject, irqPin);
|
||||
gotInterrupt = false;
|
||||
}
|
||||
// if we received an interrupt while interrupts were disabled
|
||||
// we still deliver it the next time interrupts get enabled
|
||||
// not sure if everyone agrees with this logic though
|
||||
} catch (RuntimeException e) {
|
||||
// make sure we're not busy spinning on error
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} while (!Thread.currentThread().isInterrupted());
|
||||
} catch (Exception e) {
|
||||
// terminate the thread on any unexpected exception that might occur
|
||||
System.err.println("Terminating interrupt handling for pin " + irqPin + " after catching: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}, "GPIO" + pin + " IRQ");
|
||||
|
||||
t.setPriority(Thread.MAX_PRIORITY);
|
||||
t.start();
|
||||
|
||||
irqThreads.put(pin, t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the GPIO pin number can be valid
|
||||
*
|
||||
* Board-specific classes, such as RPI, assign -1 to pins that carry power,
|
||||
* ground and the like.
|
||||
* @param pin GPIO pin
|
||||
*/
|
||||
protected static void checkValidPin(int pin) {
|
||||
if (pin < 0) {
|
||||
throw new RuntimeException("Operation not supported on this pin");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of an input pin
|
||||
* @param pin GPIO pin
|
||||
* @return GPIO.HIGH (1) or GPIO.LOW (0)
|
||||
* @see pinMode
|
||||
* @see digitalWrite
|
||||
* @webref
|
||||
*/
|
||||
public static int digitalRead(int pin) {
|
||||
checkValidPin(pin);
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return LOW;
|
||||
}
|
||||
|
||||
String fn = String.format("/sys/class/gpio/gpio%d/value", pin);
|
||||
byte in[] = new byte[2];
|
||||
int ret = NativeInterface.readFile(fn, in);
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
} else if (1 <= ret && in[0] == '0') {
|
||||
return LOW;
|
||||
} else if (1 <= ret && in[0] == '1') {
|
||||
return HIGH;
|
||||
} else {
|
||||
System.err.print("Read " + ret + " bytes");
|
||||
if (0 < ret) {
|
||||
System.err.format(", first byte is 0x%02x" + in[0]);
|
||||
}
|
||||
System.err.println();
|
||||
throw new RuntimeException("Unexpected value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets an output pin to be either high or low
|
||||
* @param pin GPIO pin
|
||||
* @param value GPIO.HIGH (1) or GPIO.LOW (0)
|
||||
* @see pinMode
|
||||
* @see digitalRead
|
||||
* @webref
|
||||
*/
|
||||
public static void digitalWrite(int pin, int value) {
|
||||
checkValidPin(pin);
|
||||
|
||||
String out;
|
||||
if (value == LOW) {
|
||||
// values are also stored in a bitmap to make it possible to set a
|
||||
// default level per pin before enabling the output
|
||||
values.clear(pin);
|
||||
out = "0";
|
||||
} else if (value == HIGH) {
|
||||
values.set(pin);
|
||||
out = "1";
|
||||
} else {
|
||||
System.err.println("Only GPIO.LOW and GPIO.HIGH, 0 and 1, or true and false, can be used.");
|
||||
throw new IllegalArgumentException("Illegal value");
|
||||
}
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fn = String.format("/sys/class/gpio/gpio%d/value", pin);
|
||||
int ret = NativeInterface.writeFile(fn, out);
|
||||
if (ret < 0) {
|
||||
if (ret != -2) { // ENOENT, pin might not yet be exported
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param value true or false
|
||||
*/
|
||||
public static void digitalWrite(int pin, boolean value) {
|
||||
if (value) {
|
||||
digitalWrite(pin, HIGH);
|
||||
} else {
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables an interrupt for an input pin
|
||||
* @param pin GPIO pin
|
||||
* @see enableInterrupt
|
||||
* @see waitForInterrupt
|
||||
*/
|
||||
protected static void disableInterrupt(int pin) {
|
||||
enableInterrupt(pin, NONE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enables an interrupt for an input pin
|
||||
* @param pin GPIO pin
|
||||
* @param mode what to wait for: GPIO.CHANGE, GPIO.FALLING or GPIO.RISING
|
||||
* @see waitForInterrupt
|
||||
* @see disableInterrupt
|
||||
*/
|
||||
protected static void enableInterrupt(int pin, int mode) {
|
||||
checkValidPin(pin);
|
||||
|
||||
String out;
|
||||
if (mode == NONE) {
|
||||
out = "none";
|
||||
} else if (mode == CHANGE) {
|
||||
out = "both";
|
||||
} else if (mode == FALLING) {
|
||||
out = "falling";
|
||||
} else if (mode == RISING) {
|
||||
out = "rising";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown mode");
|
||||
}
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fn = String.format("/sys/class/gpio/gpio%d/edge", pin);
|
||||
int ret = NativeInterface.writeFile(fn, out);
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your called pinMode on the input pin");
|
||||
}
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allows interrupts to happen
|
||||
* @see attachInterrupt
|
||||
* @see noInterrupts
|
||||
* @see releaseInterrupt
|
||||
* @webref
|
||||
*/
|
||||
public static void interrupts() {
|
||||
serveInterrupts = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prevents interrupts from happpening
|
||||
* @see attachInterrupt
|
||||
* @see interrupts
|
||||
* @see releaseInterrupt
|
||||
* @webref
|
||||
*/
|
||||
public static void noInterrupts() {
|
||||
serveInterrupts = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures a pin to act either as input or output
|
||||
* @param pin GPIO pin
|
||||
* @param mode GPIO.INPUT, GPIO.INPUT_PULLUP, GPIO.INPUT_PULLDOWN, or GPIO.OUTPUT
|
||||
* @see digitalRead
|
||||
* @see digitalWrite
|
||||
* @see releasePin
|
||||
* @webref
|
||||
*/
|
||||
public static void pinMode(int pin, int mode) {
|
||||
checkValidPin(pin);
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// export pin through sysfs
|
||||
String fn = "/sys/class/gpio/export";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString(pin));
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your kernel is compiled with GPIO_SYSFS enabled");
|
||||
}
|
||||
if (ret == -22) { // EINVAL
|
||||
System.err.println("GPIO pin " + pin + " does not seem to be available on your platform");
|
||||
}
|
||||
if (ret != -16) { // EBUSY, returned when the pin is already exported
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
// set direction and default level for outputs
|
||||
fn = String.format("/sys/class/gpio/gpio%d/direction", pin);
|
||||
String out;
|
||||
if (mode == INPUT) {
|
||||
out = "in";
|
||||
|
||||
// attempt to disable any pre-set pullups on the Raspberry Pi
|
||||
NativeInterface.raspbianGpioMemSetPinBias(pin, mode);
|
||||
|
||||
} else if (mode == OUTPUT) {
|
||||
if (values.get(pin)) {
|
||||
out = "high";
|
||||
} else {
|
||||
out = "low";
|
||||
}
|
||||
} else if (mode == INPUT_PULLUP || mode == INPUT_PULLDOWN) {
|
||||
out = "in";
|
||||
|
||||
// attempt to set pullups on the Raspberry Pi
|
||||
ret = NativeInterface.raspbianGpioMemSetPinBias(pin, mode);
|
||||
if (ret == -2) { // NOENT
|
||||
System.err.println("Setting pullup or pulldown resistors is currently only supported on the Raspberry Pi running Raspbian. Continuing without.");
|
||||
} else if (ret < 0) {
|
||||
System.err.println("Error setting pullup or pulldown resistors: " + NativeInterface.getError(ret) + ". Continuing without.");
|
||||
}
|
||||
// currently this can't be done in a non-platform-specific way, see
|
||||
// http://lists.infradead.org/pipermail/linux-rpi-kernel/2015-August/002146.html
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown mode");
|
||||
}
|
||||
|
||||
// we need to give udev some time to change the file permissions behind our back
|
||||
// retry for 500ms when writing to the file fails with -EACCES
|
||||
long start = System.currentTimeMillis();
|
||||
do {
|
||||
ret = NativeInterface.writeFile(fn, out);
|
||||
if (ret == -13) {
|
||||
Thread.yield();
|
||||
}
|
||||
} while (ret == -13 && System.currentTimeMillis()-start < 500);
|
||||
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops listening for interrupts on an input pin
|
||||
* @param pin GPIO pin
|
||||
* @see attachInterrupt
|
||||
* @see noInterrupts
|
||||
* @see interrupts
|
||||
* @webref
|
||||
*/
|
||||
public static void releaseInterrupt(int pin) {
|
||||
Thread t = irqThreads.get(pin);
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
t.interrupt();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Error joining thread in releaseInterrupt: " + e.getMessage());
|
||||
}
|
||||
t = null;
|
||||
irqThreads.remove(pin);
|
||||
|
||||
disableInterrupt(pin);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives ownership of a pin back to the operating system
|
||||
* @param pin GPIO pin
|
||||
* @see pinMode
|
||||
* @webref
|
||||
*/
|
||||
public static void releasePin(int pin) {
|
||||
checkValidPin(pin);
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fn = "/sys/class/gpio/unexport";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString(pin));
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your kernel is compiled with GPIO_SYSFS enabled");
|
||||
}
|
||||
// EINVAL is returned when trying to unexport pins that weren't exported to begin with, ignore this case
|
||||
if (ret != -22) {
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for the value of an input pin to change
|
||||
* @param pin GPIO pin
|
||||
* @param mode what to wait for: GPIO.CHANGE, GPIO.FALLING or GPIO.RISING
|
||||
* @webref
|
||||
*/
|
||||
public static void waitFor(int pin, int mode) {
|
||||
waitFor(pin, mode, -1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for the value of an input pin to change
|
||||
*
|
||||
* This function will throw a RuntimeException in case of a timeout.
|
||||
* @param timeout don't wait more than timeout milliseconds
|
||||
* @webref
|
||||
*/
|
||||
public static void waitFor(int pin, int mode, int timeout) {
|
||||
enableInterrupt(pin, mode);
|
||||
if (waitForInterrupt(pin, timeout) == false) {
|
||||
throw new RuntimeException("Timeout occurred");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean waitForInterrupt(int pin, int mode, int timeout) {
|
||||
throw new RuntimeException("The waitForInterrupt function has been renamed to waitFor. Please update your sketch accordingly.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for the value of an input pin to change
|
||||
*
|
||||
* Make sure to setup the interrupt with enableInterrupt() before calling
|
||||
* this function. A timeout value of -1 waits indefinitely.
|
||||
* @param pin GPIO pin
|
||||
* @param timeout don't wait more than timeout milliseconds
|
||||
* @return true if the interrupt occured, false if the timeout occured
|
||||
* @see enableInterrupt
|
||||
* @see disableInterrupt
|
||||
*/
|
||||
protected static boolean waitForInterrupt(int pin, int timeout) {
|
||||
checkValidPin(pin);
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
// pretend the interrupt happens after 200ms
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {}
|
||||
return true;
|
||||
}
|
||||
|
||||
String fn = String.format("/sys/class/gpio/gpio%d/value", pin);
|
||||
int ret = NativeInterface.pollDevice(fn, timeout);
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your called pinMode on the input pin");
|
||||
}
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
} else if (ret == 0) {
|
||||
// timeout
|
||||
return false;
|
||||
} else {
|
||||
// interrupt
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.io.NativeInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class I2C {
|
||||
|
||||
protected String dev;
|
||||
protected int handle;
|
||||
protected int slave;
|
||||
protected byte[] out;
|
||||
protected boolean transmitting;
|
||||
|
||||
|
||||
/**
|
||||
* Opens an I2C interface as master
|
||||
* @param dev interface name
|
||||
* @see list
|
||||
* @webref
|
||||
*/
|
||||
public I2C(String dev) {
|
||||
NativeInterface.loadLibrary();
|
||||
this.dev = dev;
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
handle = NativeInterface.openDevice("/dev/" + dev);
|
||||
if (handle < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begins a transmission to an attached device
|
||||
* @see write
|
||||
* @see read
|
||||
* @see endTransmission
|
||||
* @webref
|
||||
*/
|
||||
public void beginTransmission(int slave) {
|
||||
// addresses 120 (0x78) to 127 are additionally reserved
|
||||
if (0x78 <= slave) {
|
||||
System.err.println("beginTransmission expects a 7 bit address, try shifting one bit to the right");
|
||||
throw new IllegalArgumentException("Illegal address");
|
||||
}
|
||||
this.slave = slave;
|
||||
transmitting = true;
|
||||
out = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the I2C device
|
||||
* @webref
|
||||
*/
|
||||
public void close() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeInterface.closeDevice(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ends the current transmissions
|
||||
* @see beginTransmission
|
||||
* @see write
|
||||
* @webref
|
||||
*/
|
||||
public void endTransmission() {
|
||||
if (!transmitting) {
|
||||
// silently ignore this case
|
||||
return;
|
||||
}
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// implement these flags if needed: https://github.com/raspberrypi/linux/blob/rpi-patches/Documentation/i2c/i2c-protocol
|
||||
int ret = NativeInterface.transferI2c(handle, slave, out, null);
|
||||
transmitting = false;
|
||||
out = null;
|
||||
if (ret < 0) {
|
||||
if (ret == -5 | ret == -121) { // EIO | EREMOTEIO
|
||||
System.err.println("The device did not respond. Check the cabling and whether you are using the correct address.");
|
||||
}
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lists all available I2C interfaces
|
||||
* @return String array
|
||||
* @webref
|
||||
*/
|
||||
public static String[] list() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
// as on the Raspberry Pi
|
||||
return new String[]{ "i2c-1" };
|
||||
}
|
||||
|
||||
ArrayList<String> devs = new ArrayList<String>();
|
||||
File dir = new File("/dev");
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.getName().startsWith("i2c-")) {
|
||||
devs.add(file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
// listFiles() does not guarantee ordering
|
||||
String[] tmp = devs.toArray(new String[devs.size()]);
|
||||
Arrays.sort(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads bytes from the attached device
|
||||
* @param len number of bytes to read
|
||||
* @return bytes read from device
|
||||
* @see beginTransmission
|
||||
* @see write
|
||||
* @see endTransmission
|
||||
* @webref
|
||||
*/
|
||||
public byte[] read(int len) {
|
||||
if (!transmitting) {
|
||||
throw new RuntimeException("beginTransmisson has not been called");
|
||||
}
|
||||
|
||||
byte[] in = new byte[len];
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return in;
|
||||
}
|
||||
|
||||
int ret = NativeInterface.transferI2c(handle, slave, out, in);
|
||||
transmitting = false;
|
||||
out = null;
|
||||
if (ret < 0) {
|
||||
if (ret == -5 | ret == -121) { // EIO | EREMOTEIO
|
||||
System.err.println("The device did not respond. Check the cabling and whether you are using the correct address.");
|
||||
}
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds bytes to be written to the device
|
||||
* @param out bytes to be written
|
||||
* @see beginTransmission
|
||||
* @see read
|
||||
* @see endTransmission
|
||||
* @webref
|
||||
*/
|
||||
public void write(byte[] out) {
|
||||
if (!transmitting) {
|
||||
throw new RuntimeException("beginTransmisson has not been called");
|
||||
}
|
||||
|
||||
if (this.out == null) {
|
||||
this.out = out;
|
||||
} else {
|
||||
byte[] tmp = new byte[this.out.length + out.length];
|
||||
System.arraycopy(this.out, 0, tmp, 0, this.out.length);
|
||||
System.arraycopy(out, 0, tmp, this.out.length, out.length);
|
||||
this.out = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds bytes to be written to the attached device
|
||||
* @param out string to be written
|
||||
* @see beginTransmission
|
||||
* @see read
|
||||
* @see endTransmission
|
||||
*/
|
||||
public void write(String out) {
|
||||
write(out.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a byte to be written to the attached device
|
||||
* @param out single byte to be written, e.g. numeric literal (0 to 255, or -128 to 127)
|
||||
* @see beginTransmission
|
||||
* @see read
|
||||
* @see endTransmission
|
||||
*/
|
||||
public void write(int out) {
|
||||
if (out < -128 || 255 < out) {
|
||||
System.err.println("The write function can only operate on a single byte at a time. Call it with a value from 0 to 255, or -128 to 127.");
|
||||
throw new RuntimeException("Argument does not fit into a single byte");
|
||||
}
|
||||
byte[] tmp = new byte[1];
|
||||
tmp[0] = (byte)out;
|
||||
write(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a byte to be written to the attached device
|
||||
* @param out single byte to be written
|
||||
* @see beginTransmission
|
||||
* @see read
|
||||
* @see endTransmission
|
||||
*/
|
||||
public void write(byte out) {
|
||||
// cast to (unsigned) int
|
||||
write(out & 0xff);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.io.NativeInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class LED {
|
||||
|
||||
protected String dev;
|
||||
protected int maxBrightness;
|
||||
protected int prevBrightness;
|
||||
protected String prevTrigger;
|
||||
|
||||
|
||||
/**
|
||||
* Opens a LED device
|
||||
* @param dev device name
|
||||
* @see list
|
||||
* @webref
|
||||
*/
|
||||
public LED(String dev) {
|
||||
NativeInterface.loadLibrary();
|
||||
this.dev = dev;
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// read maximum brightness
|
||||
try {
|
||||
Path path = Paths.get("/sys/class/leds/" + dev + "/max_brightness");
|
||||
String tmp = new String(Files.readAllBytes(path));
|
||||
maxBrightness = Integer.parseInt(tmp.trim());
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
throw new RuntimeException("Unable to read maximum brightness");
|
||||
}
|
||||
|
||||
// read current trigger setting to be able to restore it later
|
||||
try {
|
||||
Path path = Paths.get("/sys/class/leds/" + dev + "/trigger");
|
||||
String tmp = new String(Files.readAllBytes(path));
|
||||
int start = tmp.indexOf('[');
|
||||
int end = tmp.indexOf(']', start);
|
||||
if (start != -1 && end != -1) {
|
||||
prevTrigger = tmp.substring(start+1, end);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
throw new RuntimeException("Unable to read trigger setting");
|
||||
}
|
||||
|
||||
// read current brightness to be able to restore it later
|
||||
try {
|
||||
Path path = Paths.get("/sys/class/leds/" + dev + "/brightness");
|
||||
String tmp = new String(Files.readAllBytes(path));
|
||||
prevBrightness = Integer.parseInt(tmp.trim());
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
throw new RuntimeException("Unable to read current brightness");
|
||||
}
|
||||
|
||||
// disable trigger
|
||||
String fn = "/sys/class/leds/" + dev + "/trigger";
|
||||
int ret = NativeInterface.writeFile(fn, "none");
|
||||
if (ret < 0) {
|
||||
if (ret == -13) { // EACCES
|
||||
System.err.println("You might need to install a custom udev rule to allow regular users to modify /sys/class/leds/*.");
|
||||
}
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the brightness
|
||||
* @param bright 0.0 (off) to 1.0 (maximum)
|
||||
* @webref
|
||||
*/
|
||||
public void brightness(float bright) {
|
||||
if (bright < 0.0 || 1.0 < bright) {
|
||||
System.err.println("Brightness must be between 0.0 and 1.0.");
|
||||
throw new IllegalArgumentException("Illegal argument");
|
||||
}
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fn = "/sys/class/leds/" + dev + "/brightness";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString((int)(bright * maxBrightness)));
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restores the previous state
|
||||
* @webref
|
||||
*/
|
||||
public void close() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// restore previous settings
|
||||
String fn = "/sys/class/leds/" + dev + "/brightness";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString(prevBrightness));
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
|
||||
fn = "/sys/class/leds/" + dev + "/trigger";
|
||||
ret = NativeInterface.writeFile(fn, prevTrigger);
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lists all available LED devices
|
||||
* @return String array
|
||||
* @webref
|
||||
*/
|
||||
public static String[] list() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
// as on the Raspberry Pi
|
||||
return new String[]{ "led0", "led1" };
|
||||
}
|
||||
|
||||
ArrayList<String> devs = new ArrayList<>();
|
||||
File dir = new File("/sys/class/leds");
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
devs.add(file.getName());
|
||||
}
|
||||
}
|
||||
// listFiles() does not guarantee ordering
|
||||
String[] tmp = devs.toArray(new String[devs.size()]);
|
||||
Arrays.sort(tmp);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
|
||||
public class NativeInterface {
|
||||
|
||||
protected static boolean loaded = false;
|
||||
protected static boolean alwaysSimulate = false;
|
||||
|
||||
public static void loadLibrary() {
|
||||
if (!loaded) {
|
||||
if (isSimulated()) {
|
||||
System.err.println("The Processing I/O library is not supported on this platform. Instead of values from actual hardware ports, your sketch will only receive stand-in values that allow you to test the remainder of its functionality.");
|
||||
} else {
|
||||
System.loadLibrary("processing-io");
|
||||
}
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void alwaysSimulate() {
|
||||
alwaysSimulate = true;
|
||||
}
|
||||
|
||||
public static boolean isSimulated() {
|
||||
return alwaysSimulate ||
|
||||
!"Linux".equals(System.getProperty("os.name"));
|
||||
}
|
||||
|
||||
|
||||
public static native int openDevice(String fn);
|
||||
public static native String getError(int errno);
|
||||
public static native int closeDevice(int handle);
|
||||
|
||||
// the following two functions were done in native code to get access to the
|
||||
// specifc error number (errno) that might occur
|
||||
public static native int readFile(String fn, byte[] in);
|
||||
public static native int writeFile(String fn, byte[] out);
|
||||
public static int writeFile(String fn, String out) {
|
||||
return writeFile(fn, out.getBytes());
|
||||
}
|
||||
|
||||
/* GPIO */
|
||||
public static native int raspbianGpioMemRead(int offset);
|
||||
public static native int raspbianGpioMemWrite(int offset, int mask, int value);
|
||||
public static native int raspbianGpioMemSetPinBias(int gpio, int mode);
|
||||
public static native int pollDevice(String fn, int timeout);
|
||||
/* I2C */
|
||||
public static native int transferI2c(int handle, int slave, byte[] out, byte[] in);
|
||||
/* SoftwareServo */
|
||||
public static native long servoStartThread(int gpio, int pulse, int period);
|
||||
public static native int servoUpdateThread(long handle, int pulse, int period);
|
||||
public static native int servoStopThread(long handle);
|
||||
/* SPI */
|
||||
public static native int setSpiSettings(int handle, int maxSpeed, int dataOrder, int mode);
|
||||
public static native int transferSpi(int handle, byte[] out, byte[] in);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.io.NativeInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class PWM {
|
||||
|
||||
int channel;
|
||||
String chip;
|
||||
|
||||
|
||||
/**
|
||||
* Opens a PWM channel
|
||||
* @param channel PWM channel
|
||||
* @see list
|
||||
* @webref
|
||||
*/
|
||||
public PWM(String channel) {
|
||||
NativeInterface.loadLibrary();
|
||||
|
||||
int pos = channel.indexOf("/pwm");
|
||||
if (pos == -1) {
|
||||
throw new IllegalArgumentException("Unsupported channel");
|
||||
}
|
||||
chip = channel.substring(0, pos);
|
||||
this.channel = Integer.parseInt(channel.substring(pos+4));
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// export channel through sysfs
|
||||
String fn = "/sys/class/pwm/" + chip + "/export";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString(this.channel));
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your kernel is compiled with PWM_SYSFS enabled and you have the necessary PWM driver for your platform");
|
||||
}
|
||||
// XXX: check
|
||||
if (ret == -22) { // EINVAL
|
||||
System.err.println("PWM channel " + channel + " does not seem to be available on your platform");
|
||||
}
|
||||
// XXX: check
|
||||
if (ret != -16) { // EBUSY, returned when the pin is already exported
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
// delay to give udev a chance to change the file permissions behind our back
|
||||
// there should really be a cleaner way for this
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables the PWM output
|
||||
* @webref
|
||||
*/
|
||||
public void clear() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fn = String.format("/sys/class/pwm/%s/pwm%d/enable", chip, channel);
|
||||
int ret = NativeInterface.writeFile(fn, "0");
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives ownership of a channel back to the operating system
|
||||
* @webref
|
||||
*/
|
||||
public void close() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: implicit clear()?
|
||||
// XXX: also check GPIO
|
||||
|
||||
String fn = "/sys/class/pwm/" + chip + "/unexport";
|
||||
int ret = NativeInterface.writeFile(fn, Integer.toString(channel));
|
||||
if (ret < 0) {
|
||||
if (ret == -2) { // ENOENT
|
||||
System.err.println("Make sure your kernel is compiled with PWM_SYSFS enabled and you have the necessary PWM driver for your platform");
|
||||
}
|
||||
// XXX: check
|
||||
// EINVAL is also returned when trying to unexport pins that weren't exported to begin with
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lists all available PWM channels
|
||||
* @return String array
|
||||
* @webref
|
||||
*/
|
||||
public static String[] list() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return new String[]{ "pwmchip0/pwm0", "pwmchip0/pwm1" };
|
||||
}
|
||||
|
||||
ArrayList<String> devs = new ArrayList<String>();
|
||||
File dir = new File("/sys/class/pwm");
|
||||
File[] chips = dir.listFiles();
|
||||
if (chips != null) {
|
||||
for (File chip : chips) {
|
||||
// get the number of supported channels
|
||||
try {
|
||||
Path path = Paths.get("/sys/class/pwm/" + chip.getName() + "/npwm");
|
||||
String tmp = new String(Files.readAllBytes(path));
|
||||
int npwm = Integer.parseInt(tmp.trim());
|
||||
for (int i=0; i < npwm; i++) {
|
||||
devs.add(chip.getName() + "/pwm" + i);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// listFiles() does not guarantee ordering
|
||||
String[] tmp = devs.toArray(new String[devs.size()]);
|
||||
Arrays.sort(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enables the PWM output
|
||||
* @param period cycle period in Hz
|
||||
* @param duty duty cycle, 0.0 (always off) to 1.0 (always on)
|
||||
* @webref
|
||||
*/
|
||||
public void set(int period, float duty) {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set period
|
||||
String fn = fn = String.format("/sys/class/pwm/%s/pwm%d/period", chip, channel);
|
||||
// convert to nanoseconds
|
||||
int ret = NativeInterface.writeFile(fn, String.format("%d", (int)(1000000000 / period)));
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
|
||||
// set duty cycle
|
||||
fn = fn = String.format("/sys/class/pwm/%s/pwm%d/duty_cycle", chip, channel);
|
||||
if (duty < 0.0 || 1.0 < duty) {
|
||||
System.err.println("Duty cycle must be between 0.0 and 1.0.");
|
||||
throw new IllegalArgumentException("Illegal argument");
|
||||
}
|
||||
// convert to nanoseconds
|
||||
ret = NativeInterface.writeFile(fn, String.format("%d", (int)((1000000000 * duty) / period)));
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
|
||||
// enable output
|
||||
fn = String.format("/sys/class/pwm/%s/pwm%d/enable", chip, channel);
|
||||
ret = NativeInterface.writeFile(fn, "1");
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enables the PWM output with a preset period of 1 kHz
|
||||
* @webref
|
||||
*/
|
||||
public void set(float duty) {
|
||||
set(1000, duty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider as part of GSoC 2015
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.io.NativeInterface;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class SPI {
|
||||
|
||||
/**
|
||||
* CPOL=0, CPHA=0, most common
|
||||
*/
|
||||
public static final int MODE0 = 0;
|
||||
/**
|
||||
* CPOL=0, CPHA=1
|
||||
*/
|
||||
public static final int MODE1 = 1;
|
||||
/**
|
||||
* CPOL=1, CPHA=0
|
||||
*/
|
||||
public static final int MODE2 = 2;
|
||||
/**
|
||||
* CPOL=1, CPHA=1
|
||||
*/
|
||||
public static final int MODE3 = 3;
|
||||
/**
|
||||
* most significant bit first, most common
|
||||
*/
|
||||
public static final int MSBFIRST = 0;
|
||||
/**
|
||||
* least significant bit first
|
||||
*/
|
||||
public static final int LSBFIRST = 1;
|
||||
|
||||
protected int dataOrder = 0;
|
||||
protected String dev;
|
||||
protected int handle;
|
||||
protected int maxSpeed = 500000;
|
||||
protected int mode = 0;
|
||||
protected static Map<String, String> settings = new HashMap<String, String>();
|
||||
|
||||
|
||||
/**
|
||||
* Opens an SPI interface as master
|
||||
* @param dev device name
|
||||
* @see list
|
||||
* @webref
|
||||
*/
|
||||
public SPI(String dev) {
|
||||
NativeInterface.loadLibrary();
|
||||
this.dev = dev;
|
||||
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
handle = NativeInterface.openDevice("/dev/" + dev);
|
||||
if (handle < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the SPI interface
|
||||
* @webref
|
||||
*/
|
||||
public void close() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeInterface.closeDevice(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lists all available SPI interfaces
|
||||
* @return String array
|
||||
* @webref
|
||||
*/
|
||||
public static String[] list() {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
// as on the Raspberry Pi
|
||||
return new String[]{ "spidev0.0", "spidev0.1" };
|
||||
}
|
||||
|
||||
ArrayList<String> devs = new ArrayList<String>();
|
||||
File dir = new File("/dev");
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.getName().startsWith("spidev")) {
|
||||
devs.add(file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
// listFiles() does not guarantee ordering
|
||||
String[] tmp = devs.toArray(new String[devs.size()]);
|
||||
Arrays.sort(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures the SPI interface
|
||||
* @param maxSpeed maximum transmission rate in Hz, 500000 (500 kHz) is a resonable default
|
||||
* @param dataOrder whether data is send with the first- or least-significant bit first (SPI.MSBFIRST or SPI.LSBFIRST, the former is more common)
|
||||
* @param mode <a href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase">SPI.MODE0 to SPI.MODE3</a>
|
||||
* @webref
|
||||
*/
|
||||
public void settings(int maxSpeed, int dataOrder, int mode) {
|
||||
this.maxSpeed = maxSpeed;
|
||||
this.dataOrder = dataOrder;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transfers data over the SPI bus
|
||||
* @param out bytes to send
|
||||
* @return bytes read in (array is the same length as out)
|
||||
* @webref
|
||||
*/
|
||||
public byte[] transfer(byte[] out) {
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return new byte[out.length];
|
||||
}
|
||||
|
||||
// track the current setting per device across multiple instances
|
||||
String curSettings = maxSpeed + "-" + dataOrder + "-" + mode;
|
||||
if (!curSettings.equals(settings.get(dev))) {
|
||||
int ret = NativeInterface.setSpiSettings(handle, maxSpeed, dataOrder, mode);
|
||||
if (ret < 0) {
|
||||
System.err.println(NativeInterface.getError(handle));
|
||||
throw new RuntimeException("Error updating device configuration");
|
||||
}
|
||||
settings.put(dev, curSettings);
|
||||
}
|
||||
|
||||
byte[] in = new byte[out.length];
|
||||
int transferred = NativeInterface.transferSpi(handle, out, in);
|
||||
if (transferred < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(transferred));
|
||||
} else if (transferred < out.length) {
|
||||
throw new RuntimeException("Fewer bytes transferred than requested: " + transferred);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transfers data over the SPI bus
|
||||
* @param out string to send
|
||||
* @return bytes read in (array is the same length as out)
|
||||
*/
|
||||
public byte[] transfer(String out) {
|
||||
return transfer(out.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transfers data over the SPI bus
|
||||
* @param out single byte to send, e.g. numeric literal (0 to 255, or -128 to 127)
|
||||
* @return bytes read in (array is the same length as out)
|
||||
*/
|
||||
public byte[] transfer(int out) {
|
||||
if (out < -128 || 255 < out) {
|
||||
System.err.println("The transfer function can only operate on a single byte at a time. Call it with a value from 0 to 255, or -128 to 127.");
|
||||
throw new RuntimeException("Argument does not fit into a single byte");
|
||||
}
|
||||
byte[] tmp = new byte[1];
|
||||
tmp[0] = (byte)out;
|
||||
return transfer(tmp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transfers data over the SPI bus
|
||||
* @param out single byte to send
|
||||
* @return bytes read in (array is the same length as out)
|
||||
*/
|
||||
public byte[] transfer(byte out) {
|
||||
// cast to (unsigned) int
|
||||
return transfer(out & 0xff);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Copyright (c) The Processing Foundation 2015
|
||||
Hardware I/O library developed by Gottfried Haider
|
||||
|
||||
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.io;
|
||||
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
/**
|
||||
* @webref
|
||||
*/
|
||||
public class SoftwareServo {
|
||||
|
||||
public static final int DEFAULT_MIN_PULSE = 544;
|
||||
public static final int DEFAULT_MAX_PULSE = 2400;
|
||||
|
||||
protected int pin = -1; // gpio number (-1 .. not attached)
|
||||
protected long handle = -1; // native thread id (<0 .. not started)
|
||||
protected int period = 20000; // 20 ms (50 Hz)
|
||||
protected int minPulse = 0; // minimum pulse width in microseconds
|
||||
protected int maxPulse = 0; // maximum pulse width in microseconds
|
||||
protected int pulse = 0; // current pulse in microseconds
|
||||
|
||||
|
||||
/**
|
||||
* Opens a servo motor
|
||||
* @param parent typically use "this"
|
||||
* @webref
|
||||
*/
|
||||
public SoftwareServo(PApplet parent) {
|
||||
NativeInterface.loadLibrary();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes a servo motor
|
||||
* @webref
|
||||
*/
|
||||
public void close() {
|
||||
detach();
|
||||
}
|
||||
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attaches a servo motor to a GPIO pin
|
||||
* @param pin GPIO pin
|
||||
* @webref
|
||||
*/
|
||||
public void attach(int pin) {
|
||||
detach();
|
||||
this.pin = pin;
|
||||
this.minPulse = DEFAULT_MIN_PULSE;
|
||||
this.maxPulse = DEFAULT_MAX_PULSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attaches a servo motor to a GPIO pin using custom pulse widths
|
||||
* @param minPulse minimum pulse width in microseconds (default: 544, same as on Arduino)
|
||||
* @param maxPulse maximum pulse width in microseconds (default: 2400, same as on Arduino)
|
||||
* @webref
|
||||
*/
|
||||
public void attach(int pin, int minPulse, int maxPulse) {
|
||||
detach();
|
||||
this.pin = pin;
|
||||
this.minPulse = minPulse;
|
||||
this.maxPulse = maxPulse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves a servo motor to a given orientation
|
||||
* @param angle angle in degrees (controls speed and direction on continuous-rotation servos)
|
||||
* @webref
|
||||
*/
|
||||
public void write(float angle) {
|
||||
if (attached() == false) {
|
||||
System.err.println("You need to call attach(pin) before write(angle).");
|
||||
throw new RuntimeException("Servo is not attached");
|
||||
}
|
||||
|
||||
if (angle < 0 || 180 < angle) {
|
||||
System.err.println("Only degree values between 0 and 180 can be used.");
|
||||
throw new IllegalArgumentException("Illegal value");
|
||||
}
|
||||
pulse = (int)(minPulse + (angle/180.0) * (maxPulse-minPulse));
|
||||
|
||||
if (handle < 0) {
|
||||
// start a new thread
|
||||
GPIO.pinMode(pin, GPIO.OUTPUT);
|
||||
if (NativeInterface.isSimulated()) {
|
||||
return;
|
||||
}
|
||||
handle = NativeInterface.servoStartThread(pin, pulse, period);
|
||||
if (handle < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError((int)handle));
|
||||
}
|
||||
} else {
|
||||
// thread already running
|
||||
int ret = NativeInterface.servoUpdateThread(handle, pulse, period);
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether a servo motor is attached to a pin
|
||||
* @return true if attached, false is not
|
||||
* @webref
|
||||
*/
|
||||
public boolean attached() {
|
||||
return (pin != -1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detatches a servo motor from a GPIO pin
|
||||
* @webref
|
||||
*/
|
||||
public void detach() {
|
||||
if (0 <= handle) {
|
||||
// stop thread
|
||||
int ret = NativeInterface.servoStopThread(handle);
|
||||
GPIO.pinMode(pin, GPIO.INPUT);
|
||||
handle = -1;
|
||||
pin = -1;
|
||||
if (ret < 0) {
|
||||
throw new RuntimeException(NativeInterface.getError(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>processing-net</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,295 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=1
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=2
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=2
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_processing
|
||||
formatter_settings_version=12
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Processing Net Library" default="build">
|
||||
|
||||
<target name="clean" description="Clean the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="library/net.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../../../core/library/core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built" message="Please build the core library first and make sure it sits in ../../../core/library/core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
<javac source="1.8"
|
||||
target="1.8"
|
||||
srcdir="src" destdir="bin"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/library/core.jar"
|
||||
nowarn="true"
|
||||
compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
|
||||
<compilerclasspath path="../../mode/org.eclipse.jdt.core.jar;
|
||||
../../mode/jdtCompilerAdapter.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build net library">
|
||||
<jar basedir="bin" destfile="library/net.jar" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Chat Server
|
||||
* by Tom Igoe.
|
||||
*
|
||||
* Press the mouse to stop the server.
|
||||
*/
|
||||
|
||||
|
||||
import processing.net.*;
|
||||
|
||||
int port = 10002;
|
||||
boolean myServerRunning = true;
|
||||
int bgColor = 0;
|
||||
int direction = 1;
|
||||
int textLine = 60;
|
||||
|
||||
Server myServer;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(400, 400);
|
||||
textFont(createFont("SanSerif", 16));
|
||||
myServer = new Server(this, port); // Starts a myServer on port 10002
|
||||
background(0);
|
||||
}
|
||||
|
||||
void mousePressed()
|
||||
{
|
||||
// If the mouse clicked the myServer stops
|
||||
myServer.stop();
|
||||
myServerRunning = false;
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if (myServerRunning == true)
|
||||
{
|
||||
text("server", 15, 45);
|
||||
Client thisClient = myServer.available();
|
||||
if (thisClient != null) {
|
||||
if (thisClient.available() > 0) {
|
||||
text("mesage from: " + thisClient.ip() + " : " + thisClient.readString(), 15, textLine);
|
||||
textLine = textLine + 35;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text("server", 15, 45);
|
||||
text("stopped", 15, 65);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* HTTP Client.
|
||||
*
|
||||
* Starts a network client that connects to a server on port 80,
|
||||
* sends an HTTP 1.0 GET request, and prints the results.
|
||||
*
|
||||
* Note that this code is not necessary for simple HTTP GET request:
|
||||
* Simply calling loadStrings("http://www.processing.org") would do
|
||||
* the same thing as (and more efficiently than) this example.
|
||||
* This example is for people who might want to do something more
|
||||
* complicated later.
|
||||
*/
|
||||
|
||||
|
||||
import processing.net.*;
|
||||
|
||||
Client c;
|
||||
String data;
|
||||
|
||||
void setup() {
|
||||
size(200, 200);
|
||||
background(50);
|
||||
fill(200);
|
||||
c = new Client(this, "www.ucla.edu", 80); // Connect to server on port 80
|
||||
c.write("GET / HTTP/1.0\r\n"); // Use the HTTP "GET" command to ask for a Web page
|
||||
c.write("\r\n");
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (c.available() > 0) { // If there's incoming data from the client...
|
||||
data = c.readString(); // ...then grab it and print it
|
||||
println(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Shared Drawing Canvas (Client)
|
||||
* by Alexander R. Galloway.
|
||||
*
|
||||
* The Processing Client class is instantiated by specifying a remote
|
||||
* address and port number to which the socket connection should be made.
|
||||
* Once the connection is made, the client may read (or write) data to the server.
|
||||
* Before running this program, start the Shared Drawing Canvas (Server) program.
|
||||
*/
|
||||
|
||||
|
||||
import processing.net.*;
|
||||
|
||||
Client c;
|
||||
String input;
|
||||
int data[];
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(450, 255);
|
||||
background(204);
|
||||
stroke(0);
|
||||
frameRate(5); // Slow it down a little
|
||||
// Connect to the server's IP address and port
|
||||
c = new Client(this, "127.0.0.1", 12345); // Replace with your server's IP and port
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if (mousePressed == true) {
|
||||
// Draw our line
|
||||
stroke(255);
|
||||
line(pmouseX, pmouseY, mouseX, mouseY);
|
||||
// Send mouse coords to other person
|
||||
c.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
|
||||
}
|
||||
// Receive data from server
|
||||
if (c.available() > 0) {
|
||||
input = c.readString();
|
||||
input = input.substring(0, input.indexOf("\n")); // Only up to the newline
|
||||
data = int(split(input, ' ')); // Split values into an array
|
||||
// Draw line using received coords
|
||||
stroke(0);
|
||||
line(data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Shared Drawing Canvas (Server)
|
||||
* by Alexander R. Galloway.
|
||||
*
|
||||
* A server that shares a drawing canvas between two computers.
|
||||
* In order to open a socket connection, a server must select a
|
||||
* port on which to listen for incoming clients and through which
|
||||
* to communicate. Once the socket is established, a client may
|
||||
* connect to the server and send or receive commands and data.
|
||||
* Get this program running and then start the Shared Drawing
|
||||
* Canvas (Client) program so see how they interact.
|
||||
*/
|
||||
|
||||
|
||||
import processing.net.*;
|
||||
|
||||
Server s;
|
||||
Client c;
|
||||
String input;
|
||||
int data[];
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(450, 255);
|
||||
background(204);
|
||||
stroke(0);
|
||||
frameRate(5); // Slow it down a little
|
||||
s = new Server(this, 12345); // Start a simple server on a port
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if (mousePressed == true) {
|
||||
// Draw our line
|
||||
stroke(255);
|
||||
line(pmouseX, pmouseY, mouseX, mouseY);
|
||||
// Send mouse coords to other person
|
||||
s.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
|
||||
}
|
||||
// Receive data from client
|
||||
c = s.available();
|
||||
if (c != null) {
|
||||
input = c.readString();
|
||||
input = input.substring(0, input.indexOf("\n")); // Only up to the newline
|
||||
data = int(split(input, ' ')); // Split values into an array
|
||||
// Draw line using received coords
|
||||
stroke(0);
|
||||
line(data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
name = Network
|
||||
version = 1
|
||||
@@ -0,0 +1,744 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Client - basic network client implementation
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-2007 Ben Fry and Casey Reas
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
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.net;
|
||||
import processing.core.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client.xml )
|
||||
*
|
||||
* A client connects to a server and sends data back and forth. If anything
|
||||
* goes wrong with the connection, for example the host is not there or is
|
||||
* listening on a different port, an exception is thrown.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref net
|
||||
* @brief The client class is used to create client Objects which connect to a server to exchange data.
|
||||
* @instanceName client any variable of type Client
|
||||
* @usage Application
|
||||
* @see_external LIB_net/clientEvent
|
||||
*/
|
||||
public class Client implements Runnable {
|
||||
|
||||
protected static final int MAX_BUFFER_SIZE = 1 << 27; // 128 MB
|
||||
|
||||
PApplet parent;
|
||||
Method clientEventMethod;
|
||||
Method disconnectEventMethod;
|
||||
|
||||
volatile Thread thread;
|
||||
Socket socket;
|
||||
int port;
|
||||
String host;
|
||||
|
||||
public InputStream input;
|
||||
public OutputStream output;
|
||||
|
||||
final Object bufferLock = new Object[0];
|
||||
|
||||
byte buffer[] = new byte[32768];
|
||||
int bufferIndex;
|
||||
int bufferLast;
|
||||
|
||||
boolean disposeRegistered = false;
|
||||
|
||||
|
||||
/**
|
||||
* @param parent typically use "this"
|
||||
* @param host address of the server
|
||||
* @param port port to read/write from on the server
|
||||
*/
|
||||
public Client(PApplet parent, String host, int port) {
|
||||
this.parent = parent;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
socket = new Socket(this.host, this.port);
|
||||
input = socket.getInputStream();
|
||||
output = socket.getOutputStream();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
|
||||
parent.registerMethod("dispose", this);
|
||||
disposeRegistered = true;
|
||||
|
||||
// reflection to check whether host sketch has a call for
|
||||
// public void clientEvent(processing.net.Client)
|
||||
// which would be called each time an event comes in
|
||||
try {
|
||||
clientEventMethod =
|
||||
parent.getClass().getMethod("clientEvent", Client.class);
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
// do the same for disconnectEvent(Client c);
|
||||
try {
|
||||
disconnectEventMethod =
|
||||
parent.getClass().getMethod("disconnectEvent", Client.class);
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param socket any object of type Socket
|
||||
* @throws IOException
|
||||
*/
|
||||
public Client(PApplet parent, Socket socket) throws IOException {
|
||||
this.parent = parent;
|
||||
this.socket = socket;
|
||||
|
||||
input = socket.getInputStream();
|
||||
output = socket.getOutputStream();
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
|
||||
// reflection to check whether host sketch has a call for
|
||||
// public void clientEvent(processing.net.Client)
|
||||
// which would be called each time an event comes in
|
||||
try {
|
||||
clientEventMethod =
|
||||
parent.getClass().getMethod("clientEvent", Client.class);
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
// do the same for disconnectEvent(Client c);
|
||||
try {
|
||||
disconnectEventMethod =
|
||||
parent.getClass().getMethod("disconnectEvent", Client.class);
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_stop.xml )
|
||||
*
|
||||
* Disconnects from the server. Use to shut the connection when you're
|
||||
* finished with the Client.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @brief Disconnects from the server
|
||||
* @usage application
|
||||
*/
|
||||
public void stop() {
|
||||
if (disconnectEventMethod != null && thread != null){
|
||||
try {
|
||||
disconnectEventMethod.invoke(parent, this);
|
||||
} catch (Exception e) {
|
||||
Throwable cause = e;
|
||||
// unwrap the exception if it came from the user code
|
||||
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
||||
cause = e.getCause();
|
||||
}
|
||||
cause.printStackTrace();
|
||||
disconnectEventMethod = null;
|
||||
}
|
||||
}
|
||||
if (disposeRegistered) {
|
||||
parent.unregisterMethod("dispose", this);
|
||||
disposeRegistered = false;
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect from the server: internal use only.
|
||||
* <P>
|
||||
* This should only be called by the internal functions in PApplet,
|
||||
* use stop() instead from within your own applets.
|
||||
*/
|
||||
public void dispose() {
|
||||
thread = null;
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
input = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
output = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
socket = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
byte[] readBuffer;
|
||||
{ // make the read buffer same size as socket receive buffer so that
|
||||
// we don't waste cycles calling listeners when there is more data waiting
|
||||
int readBufferSize = 1 << 16; // 64 KB (default socket receive buffer size)
|
||||
try {
|
||||
readBufferSize = socket.getReceiveBufferSize();
|
||||
} catch (SocketException ignore) { }
|
||||
readBuffer = new byte[readBufferSize];
|
||||
}
|
||||
while (Thread.currentThread() == thread) {
|
||||
try {
|
||||
while (input != null) {
|
||||
int readCount;
|
||||
|
||||
// try to read a byte using a blocking read.
|
||||
// An exception will occur when the sketch is exits.
|
||||
try {
|
||||
readCount = input.read(readBuffer, 0, readBuffer.length);
|
||||
} catch (SocketException e) {
|
||||
System.err.println("Client SocketException: " + e.getMessage());
|
||||
// the socket had a problem reading so don't try to read from it again.
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// read returns -1 if end-of-stream occurs (for example if the host disappears)
|
||||
if (readCount == -1) {
|
||||
System.err.println("Client got end-of-stream.");
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (bufferLock) {
|
||||
int freeBack = buffer.length - bufferLast;
|
||||
if (readCount > freeBack) {
|
||||
// not enough space at the back
|
||||
int bufferLength = bufferLast - bufferIndex;
|
||||
byte[] targetBuffer = buffer;
|
||||
if (bufferLength + readCount > buffer.length) {
|
||||
// can't fit even after compacting, resize the buffer
|
||||
// find the next power of two which can fit everything in
|
||||
int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1;
|
||||
if (newSize > MAX_BUFFER_SIZE) {
|
||||
// buffer is full because client is not reading (fast enough)
|
||||
System.err.println("Client: can't receive more data, buffer is full. " +
|
||||
"Make sure you read the data from the client.");
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
targetBuffer = new byte[newSize];
|
||||
}
|
||||
// compact the buffer (either in-place or into the new bigger buffer)
|
||||
System.arraycopy(buffer, bufferIndex, targetBuffer, 0, bufferLength);
|
||||
bufferLast -= bufferIndex;
|
||||
bufferIndex = 0;
|
||||
buffer = targetBuffer;
|
||||
}
|
||||
// copy all newly read bytes into the buffer
|
||||
System.arraycopy(readBuffer, 0, buffer, bufferLast, readCount);
|
||||
bufferLast += readCount;
|
||||
}
|
||||
|
||||
// now post an event
|
||||
if (clientEventMethod != null) {
|
||||
try {
|
||||
clientEventMethod.invoke(parent, this);
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling clientEvent() for " + host);
|
||||
Throwable cause = e;
|
||||
// unwrap the exception if it came from the user code
|
||||
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
||||
cause = e.getCause();
|
||||
}
|
||||
cause.printStackTrace();
|
||||
clientEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//errorMessage("run", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_active.xml )
|
||||
*
|
||||
* Returns true if this client is still active and hasn't run
|
||||
* into any trouble.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @brief Returns true if this client is still active
|
||||
* @usage application
|
||||
*/
|
||||
public boolean active() {
|
||||
return (thread != null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_ip.xml )
|
||||
*
|
||||
* Returns the IP address of the computer to which the Client is attached.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns the IP address of the machine as a String
|
||||
*/
|
||||
public String ip() {
|
||||
if (socket != null){
|
||||
return socket.getInetAddress().getHostAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_available.xml )
|
||||
*
|
||||
* Returns the number of bytes available. When any client has bytes
|
||||
* available from the server, it returns the number of bytes.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns the number of bytes in the buffer waiting to be read
|
||||
*/
|
||||
public int available() {
|
||||
synchronized (bufferLock) {
|
||||
return (bufferLast - bufferIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_clear.xml )
|
||||
*
|
||||
* Empty the buffer, removes all the data stored there.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Clears the buffer
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (bufferLock) {
|
||||
bufferLast = 0;
|
||||
bufferIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_read.xml )
|
||||
*
|
||||
* Returns a number between 0 and 255 for the next byte that's waiting in
|
||||
* the buffer. Returns -1 if there is no byte, although this should be
|
||||
* avoided by first cheacking <b>available()</b> to see if any data is available.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns a value from the buffer
|
||||
*/
|
||||
public int read() {
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return -1;
|
||||
|
||||
int outgoing = buffer[bufferIndex++] & 0xff;
|
||||
if (bufferIndex == bufferLast) { // rewind
|
||||
bufferIndex = 0;
|
||||
bufferLast = 0;
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_readChar.xml )
|
||||
*
|
||||
* Returns the next byte in the buffer as a char. Returns -1 or 0xffff if
|
||||
* nothing is there.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns the next byte in the buffer as a char
|
||||
*/
|
||||
public char readChar() {
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return (char) (-1);
|
||||
return (char) read();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_readBytes.xml )
|
||||
*
|
||||
* Reads a group of bytes from the buffer. The version with no parameters
|
||||
* returns a byte array of all data in the buffer. This is not efficient,
|
||||
* but is easy to use. The version with the <b>byteBuffer</b> parameter is
|
||||
* more memory and time efficient. It grabs the data in the buffer and puts
|
||||
* it into the byte array passed in and returns an int value for the number
|
||||
* of bytes read. If more bytes are available than can fit into the
|
||||
* <b>byteBuffer</b>, only those that fit are read.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* <h3>Advanced</h3>
|
||||
* 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).
|
||||
*
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Reads everything in the buffer
|
||||
*/
|
||||
public byte[] readBytes() {
|
||||
synchronized (bufferLock) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h3>Advanced</h3>
|
||||
* Return a byte array of anything that's in the serial buffer
|
||||
* up to the specified maximum number of bytes.
|
||||
* 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).
|
||||
*
|
||||
* @param max the maximum number of bytes to read
|
||||
*/
|
||||
public byte[] readBytes(int max) {
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
|
||||
int length = bufferLast - bufferIndex;
|
||||
if (length > max) length = max;
|
||||
byte outgoing[] = new byte[length];
|
||||
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h3>Advanced</h3>
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param bytebuffer passed in byte array to be altered
|
||||
*/
|
||||
public int readBytes(byte bytebuffer[]) {
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
|
||||
int length = bufferLast - bufferIndex;
|
||||
if (length > bytebuffer.length) length = bytebuffer.length;
|
||||
System.arraycopy(buffer, bufferIndex, bytebuffer, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_readBytesUntil.xml )
|
||||
*
|
||||
* Reads from the port into a buffer of bytes up to and including a
|
||||
* particular character. If the character isn't in the buffer, 'null' is
|
||||
* returned. The version with no <b>byteBuffer</b> parameter returns a byte
|
||||
* array of all data up to and including the <b>interesting</b> byte. This
|
||||
* is not efficient, but is easy to use. The version with the
|
||||
* <b>byteBuffer</b> parameter is more memory and time efficient. It grabs
|
||||
* the data in the buffer and puts it into the byte array passed in and
|
||||
* returns an int value for the number of bytes read. If the byte buffer is
|
||||
* not large enough, -1 is returned and an error is printed to the message
|
||||
* area. If nothing is in the buffer, 0 is returned.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Reads from the buffer of bytes up to and including a particular character
|
||||
* @param interesting character designated to mark the end of the data
|
||||
*/
|
||||
public byte[] readBytesUntil(int interesting) {
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return null;
|
||||
|
||||
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 += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return outgoing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h3>Advanced</h3>
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param byteBuffer passed in byte array to be altered
|
||||
*/
|
||||
public int readBytesUntil(int interesting, byte byteBuffer[]) {
|
||||
byte what = (byte)interesting;
|
||||
|
||||
synchronized (bufferLock) {
|
||||
if (bufferIndex == bufferLast) return 0;
|
||||
|
||||
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 > byteBuffer.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, byteBuffer, 0, length);
|
||||
|
||||
bufferIndex += length;
|
||||
if (bufferIndex == bufferLast) {
|
||||
bufferIndex = 0; // rewind
|
||||
bufferLast = 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_readString.xml )
|
||||
*
|
||||
* Returns the all the data from the buffer as a String. This method
|
||||
* assumes the incoming characters are ASCII. If you want to transfer
|
||||
* Unicode data, 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.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns the buffer as a String
|
||||
*/
|
||||
public String readString() {
|
||||
byte b[] = readBytes();
|
||||
if (b == null) return null;
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_readStringUntil.xml )
|
||||
*
|
||||
* Combination of <b>readBytesUntil()</b> and <b>readString()</b>. Returns
|
||||
* <b>null</b> if it doesn't find what you're looking for.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* <h3>Advanced</h3>
|
||||
* <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.
|
||||
*
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Returns the buffer as a String up to and including a particular character
|
||||
* @param interesting character designated to mark the end of the data
|
||||
*/
|
||||
public String readStringUntil(int interesting) {
|
||||
byte b[] = readBytesUntil(interesting);
|
||||
if (b == null) return null;
|
||||
return new String(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Client_write.xml )
|
||||
*
|
||||
* Writes data to a server specified when constructing the client.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref client:client
|
||||
* @usage application
|
||||
* @brief Writes bytes, chars, ints, bytes[], Strings
|
||||
* @param data data to write
|
||||
*/
|
||||
public void write(int data) { // will also cover char
|
||||
try {
|
||||
output.write(data & 0xff); // for good measure do the &
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
//errorMessage("write", e);
|
||||
//e.printStackTrace();
|
||||
//dispose();
|
||||
//disconnect(e);
|
||||
e.printStackTrace();
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(byte data[]) {
|
||||
try {
|
||||
output.write(data);
|
||||
output.flush(); // hmm, not sure if a good idea
|
||||
|
||||
} catch (Exception e) { // null pointer or serial port dead
|
||||
//errorMessage("write", e);
|
||||
//e.printStackTrace();
|
||||
//disconnect(e);
|
||||
e.printStackTrace();
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h3>Advanced</h3>
|
||||
* 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)
|
||||
*
|
||||
* 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 data) {
|
||||
write(data.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle disconnect due to an Exception being thrown.
|
||||
*/
|
||||
/*
|
||||
protected void disconnect(Exception e) {
|
||||
dispose();
|
||||
if (e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* General error reporting, all corralled here just in case
|
||||
* I think of something slightly more intelligent to do.
|
||||
*/
|
||||
//public void errorMessage(String where, Exception e) {
|
||||
//parent.die("Error inside Client." + where + "()", e);
|
||||
//e.printStackTrace(System.err);
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Server - basic network server implementation
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-2007 Ben Fry and Casey Reas
|
||||
The previous version of this code was developed by Hernando Barragan
|
||||
|
||||
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.net;
|
||||
|
||||
import processing.core.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server.xml )
|
||||
*
|
||||
* A server sends and receives data to and from its associated clients
|
||||
* (other programs connected to it). When a server is started, it begins
|
||||
* listening for connections on the port specified by the <b>port</b>
|
||||
* parameter. Computers have many ports for transferring data and some are
|
||||
* commonly used so be sure to not select one of these. For example, web
|
||||
* servers usually use port 80 and POP mail uses port 110.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref net
|
||||
* @usage application
|
||||
* @brief The server class is used to create server objects which send and receives data to and from its associated clients (other programs connected to it).
|
||||
* @instanceName server any variable of type Server
|
||||
*/
|
||||
public class Server implements Runnable {
|
||||
PApplet parent;
|
||||
Method serverEventMethod;
|
||||
|
||||
volatile Thread thread;
|
||||
ServerSocket server;
|
||||
int port;
|
||||
|
||||
protected final Object clientsLock = new Object[0];
|
||||
/** Number of clients currently connected. */
|
||||
public int clientCount;
|
||||
/** Array of client objects, useful length is determined by clientCount. */
|
||||
public Client[] clients;
|
||||
|
||||
|
||||
/**
|
||||
* @param parent typically use "this"
|
||||
* @param port port used to transfer data
|
||||
*/
|
||||
public Server(PApplet parent, int port) {
|
||||
this(parent, port, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param parent typically use "this"
|
||||
* @param port port used to transfer data
|
||||
* @param host when multiple NICs are in use, the ip (or name) to bind from
|
||||
*/
|
||||
public Server(PApplet parent, int port, String host) {
|
||||
this.parent = parent;
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
if (host == null) {
|
||||
server = new ServerSocket(this.port);
|
||||
} else {
|
||||
server = new ServerSocket(this.port, 10, InetAddress.getByName(host));
|
||||
}
|
||||
//clients = new Vector();
|
||||
clients = new Client[10];
|
||||
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
|
||||
parent.registerMethod("dispose", this);
|
||||
|
||||
// reflection to check whether host applet has a call for
|
||||
// public void serverEvent(Server s, Client c);
|
||||
// which is called when a new guy connects
|
||||
try {
|
||||
serverEventMethod =
|
||||
parent.getClass().getMethod("serverEvent", Server.class, Client.class);
|
||||
} catch (Exception e) {
|
||||
// no such method, or an error.. which is fine, just ignore
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
thread = null;
|
||||
throw new RuntimeException(e);
|
||||
//errorMessage("<init>", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server_disconnect.xml )
|
||||
*
|
||||
* Disconnect a particular client.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @brief Disconnect a particular client.
|
||||
* @webref server:server
|
||||
* @param client the client to disconnect
|
||||
*/
|
||||
public void disconnect(Client client) {
|
||||
client.stop();
|
||||
synchronized (clientsLock) {
|
||||
int index = clientIndex(client);
|
||||
if (index != -1) {
|
||||
removeIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void removeIndex(int index) {
|
||||
synchronized (clientsLock) {
|
||||
clientCount--;
|
||||
// shift down the remaining clients
|
||||
for (int i = index; i < clientCount; i++) {
|
||||
clients[i] = clients[i + 1];
|
||||
}
|
||||
// mark last empty var for garbage collection
|
||||
clients[clientCount] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void disconnectAll() {
|
||||
synchronized (clientsLock) {
|
||||
for (int i = 0; i < clientCount; i++) {
|
||||
try {
|
||||
clients[i].stop();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
clients[i] = null;
|
||||
}
|
||||
clientCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void addClient(Client client) {
|
||||
synchronized (clientsLock) {
|
||||
if (clientCount == clients.length) {
|
||||
clients = (Client[]) PApplet.expand(clients);
|
||||
}
|
||||
clients[clientCount++] = client;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int clientIndex(Client client) {
|
||||
synchronized (clientsLock) {
|
||||
for (int i = 0; i < clientCount; i++) {
|
||||
if (clients[i] == client) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server_active.xml )
|
||||
*
|
||||
* Returns true if this server is still active and hasn't run
|
||||
* into any trouble.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref server:server
|
||||
* @brief Return true if this server is still active.
|
||||
*/
|
||||
public boolean active() {
|
||||
return thread != null;
|
||||
}
|
||||
|
||||
|
||||
static public String ip() {
|
||||
try {
|
||||
return InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the last index used for available. can't just cycle through
|
||||
// the clients in order from 0 each time, because if client 0 won't
|
||||
// shut up, then the rest of the clients will never be heard from.
|
||||
int lastAvailable = -1;
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server_available.xml )
|
||||
*
|
||||
* Returns the next client in line with a new message.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @brief Returns the next client in line with a new message.
|
||||
* @webref server
|
||||
* @usage application
|
||||
*/
|
||||
public Client available() {
|
||||
synchronized (clientsLock) {
|
||||
int index = lastAvailable + 1;
|
||||
if (index >= clientCount) index = 0;
|
||||
|
||||
for (int i = 0; i < clientCount; i++) {
|
||||
int which = (index + i) % clientCount;
|
||||
Client client = clients[which];
|
||||
//Check for valid client
|
||||
if (!client.active()){
|
||||
removeIndex(which); //Remove dead client
|
||||
i--; //Don't skip the next client
|
||||
//If the client has data make sure lastAvailable
|
||||
//doesn't end up skipping the next client
|
||||
which--;
|
||||
//fall through to allow data from dead clients
|
||||
//to be retreived.
|
||||
}
|
||||
if (client.available() > 0) {
|
||||
lastAvailable = which;
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server_stop.xml )
|
||||
*
|
||||
* Disconnects all clients and stops the server.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* <h3>Advanced</h3>
|
||||
* Use this to shut down the server if you finish using it while your applet
|
||||
* is still running. Otherwise, it will be automatically be shut down by the
|
||||
* host PApplet using dispose(), which is identical.
|
||||
* @brief Disconnects all clients and stops the server.
|
||||
* @webref server
|
||||
* @usage application
|
||||
*/
|
||||
public void stop() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect all clients and stop the server: internal use only.
|
||||
*/
|
||||
public void dispose() {
|
||||
thread = null;
|
||||
|
||||
if (clients != null) {
|
||||
disconnectAll();
|
||||
clientCount = 0;
|
||||
clients = null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (server != null) {
|
||||
server.close();
|
||||
server = null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (Thread.currentThread() == thread) {
|
||||
try {
|
||||
Socket socket = server.accept();
|
||||
Client client = new Client(parent, socket);
|
||||
synchronized (clientsLock) {
|
||||
addClient(client);
|
||||
if (serverEventMethod != null) {
|
||||
try {
|
||||
serverEventMethod.invoke(parent, this, client);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Disabling serverEvent() for port " + port);
|
||||
Throwable cause = e;
|
||||
// unwrap the exception if it came from the user code
|
||||
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
||||
cause = e.getCause();
|
||||
}
|
||||
cause.printStackTrace();
|
||||
serverEventMethod = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
//thrown when server.close() is called and server is waiting on accept
|
||||
System.err.println("Server SocketException: " + e.getMessage());
|
||||
thread = null;
|
||||
} catch (IOException e) {
|
||||
//errorMessage("run", e);
|
||||
e.printStackTrace();
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ( begin auto-generated from Server_write.xml )
|
||||
*
|
||||
* Writes a value to all the connected clients. It sends bytes out from the
|
||||
* Server object.
|
||||
*
|
||||
* ( end auto-generated )
|
||||
* @webref server
|
||||
* @brief Writes data to all connected clients
|
||||
* @param data data to write
|
||||
*/
|
||||
public void write(int data) { // will also cover char
|
||||
synchronized (clientsLock) {
|
||||
int index = 0;
|
||||
while (index < clientCount) {
|
||||
if (clients[index].active()) {
|
||||
clients[index].write(data);
|
||||
index++;
|
||||
} else {
|
||||
removeIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(byte data[]) {
|
||||
synchronized (clientsLock) {
|
||||
int index = 0;
|
||||
while (index < clientCount) {
|
||||
if (clients[index].active()) {
|
||||
clients[index].write(data);
|
||||
index++;
|
||||
} else {
|
||||
removeIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(String data) {
|
||||
synchronized (clientsLock) {
|
||||
int index = 0;
|
||||
while (index < clientCount) {
|
||||
if (clients[index].active()) {
|
||||
clients[index].write(data);
|
||||
index++;
|
||||
} else {
|
||||
removeIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="lib" path="library/itext.jar" sourcepath="itext-src.zip"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>processing-pdf</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,292 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=1
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=2
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=2
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
formatter_profile=_processing
|
||||
formatter_settings_version=12
|
||||
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/>
|
||||
@@ -0,0 +1,11 @@
|
||||
This library uses iText 2.1.7, which is the last LGPL/MPL version of the iText project.
|
||||
|
||||
We've used iText for several years. The license for iText has changed for subsequent versions and is no longer compatible with Processing, so we're stuck at 2.x.
|
||||
|
||||
At the iText site, there's also some [vague wording](http://lowagie.com/itext2) about legal liability for commercial projects using the 2.x series. It's not clear where this leaves us.
|
||||
|
||||
Bruno Lowagie did an enormous amount of (free) work with the iText project, and we certainly don't fault him for the new commercial license.
|
||||
|
||||
We're using iText in a very limited way--drawing to it like it's a Java Graphics2D object. There might be other options for us in this space, but it's not much of a priority.
|
||||
|
||||
Ben Fry, 12 October 2013
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Processing PDF Library" default="build">
|
||||
|
||||
<target name="clean" description="Clean the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="library/pdf.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../../../core/library/core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built" message="Please build the core library first and make sure it sits in ../../../core/library/core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
<javac source="1.8"
|
||||
target="1.8"
|
||||
srcdir="src" destdir="bin"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/library/core.jar; library/itext.jar"
|
||||
nowarn="true"
|
||||
compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
|
||||
<compilerclasspath path="../../mode/org.eclipse.jdt.core.jar;
|
||||
../../mode/jdtCompilerAdapter.jar" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build PDF library">
|
||||
<jar basedir="bin" destfile="library/pdf.jar" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* PDF Complex
|
||||
* by Marius Watz (workshop.evolutionzone.com).
|
||||
*
|
||||
* Example using PDF to output complex 3D geometry for print.
|
||||
* Press "s" to save a PDF.
|
||||
*/
|
||||
|
||||
|
||||
import processing.opengl.*;
|
||||
import processing.pdf.*;
|
||||
|
||||
// Trig lookup tables borrowed from Toxi. Cryptic but effective
|
||||
float sinLUT[];
|
||||
float cosLUT[];
|
||||
float SINCOS_PRECISION=1.0;
|
||||
int SINCOS_LENGTH= int((360.0/SINCOS_PRECISION));
|
||||
|
||||
// System data
|
||||
boolean dosave=false;
|
||||
int num;
|
||||
float pt[];
|
||||
int style[];
|
||||
|
||||
|
||||
void setup() {
|
||||
size(600, 600, OPENGL);
|
||||
frameRate(24);
|
||||
background(255);
|
||||
|
||||
// Fill the tables
|
||||
sinLUT=new float[SINCOS_LENGTH];
|
||||
cosLUT=new float[SINCOS_LENGTH];
|
||||
for (int i = 0; i < SINCOS_LENGTH; i++) {
|
||||
sinLUT[i]= (float)Math.sin(i*DEG_TO_RAD*SINCOS_PRECISION);
|
||||
cosLUT[i]= (float)Math.cos(i*DEG_TO_RAD*SINCOS_PRECISION);
|
||||
}
|
||||
|
||||
num = 150;
|
||||
pt = new float[6*num]; // rotx, roty, deg, rad, w, speed
|
||||
style = new int[2*num]; // color, render style
|
||||
|
||||
// Set up arc shapes
|
||||
int index=0;
|
||||
float prob;
|
||||
for (int i=0; i<num; i++) {
|
||||
pt[index++] = random(PI*2); // Random X axis rotation
|
||||
pt[index++] = random(PI*2); // Random Y axis rotation
|
||||
|
||||
pt[index++] = random(60,80); // Short to quarter-circle arcs
|
||||
if(random(100)>90) pt[index]=(int)random(8,27)*10;
|
||||
|
||||
pt[index++] = int(random(2,50)*5); // Radius. Space them out nicely
|
||||
|
||||
pt[index++] = random(4,32); // Width of band
|
||||
if(random(100)>90) pt[index]=random(40,60); // Width of band
|
||||
|
||||
pt[index++] = radians(random(5,30))/5; // Speed of rotation
|
||||
|
||||
// get colors
|
||||
prob = random(100);
|
||||
if(prob<30) style[i*2]=colorBlended(random(1), 255,0,100, 255,0,0, 210);
|
||||
else if(prob<70) style[i*2]=colorBlended(random(1), 0,153,255, 170,225,255, 210);
|
||||
else if(prob<90) style[i*2]=colorBlended(random(1), 200,255,0, 150,255,0, 210);
|
||||
else style[i*2]=color(255,255,255, 220);
|
||||
|
||||
if(prob<50) style[i*2]=colorBlended(random(1), 200,255,0, 50,120,0, 210);
|
||||
else if(prob<90) style[i*2]=colorBlended(random(1), 255,100,0, 255,255,0, 210);
|
||||
else style[i*2]=color(255,255,255, 220);
|
||||
|
||||
style[i*2+1]=(int)(random(100))%3;
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
|
||||
if(dosave) {
|
||||
// set up PGraphicsPDF for use with beginRaw()
|
||||
PGraphicsPDF pdf = (PGraphicsPDF)beginRaw(PDF, "pdf_complex_out.pdf");
|
||||
|
||||
// set default Illustrator stroke styles and paint background rect.
|
||||
pdf.strokeJoin(MITER);
|
||||
pdf.strokeCap(SQUARE);
|
||||
pdf.fill(0);
|
||||
pdf.noStroke();
|
||||
pdf.rect(0,0, width,height);
|
||||
}
|
||||
|
||||
background(0);
|
||||
|
||||
int index=0;
|
||||
translate(width/2,height/2,0);
|
||||
rotateX(PI/6);
|
||||
rotateY(PI/6);
|
||||
|
||||
for (int i=0; i<num; i++) {
|
||||
pushMatrix();
|
||||
|
||||
rotateX(pt[index++]);
|
||||
rotateY(pt[index++]);
|
||||
|
||||
if(style[i*2+1]==0) {
|
||||
stroke(style[i*2]);
|
||||
noFill();
|
||||
strokeWeight(1);
|
||||
arcLine(0,0, pt[index++],pt[index++],pt[index++]);
|
||||
}
|
||||
else if(style[i*2+1]==1) {
|
||||
fill(style[i*2]);
|
||||
noStroke();
|
||||
arcLineBars(0,0, pt[index++],pt[index++],pt[index++]);
|
||||
}
|
||||
else {
|
||||
fill(style[i*2]);
|
||||
noStroke();
|
||||
arc(0,0, pt[index++],pt[index++],pt[index++]);
|
||||
}
|
||||
|
||||
// increase rotation
|
||||
pt[index-5]+=pt[index]/10;
|
||||
pt[index-4]+=pt[index++]/20;
|
||||
|
||||
popMatrix();
|
||||
}
|
||||
|
||||
if(dosave) {
|
||||
endRaw();
|
||||
dosave=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get blend of two colors
|
||||
public int colorBlended(float fract,
|
||||
float r, float g, float b,
|
||||
float r2, float g2, float b2, float a) {
|
||||
|
||||
r2 = (r2 - r);
|
||||
g2 = (g2 - g);
|
||||
b2 = (b2 - b);
|
||||
return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a);
|
||||
}
|
||||
|
||||
|
||||
// Draw arc line
|
||||
public void arcLine(float x,float y,float deg,float rad,float w) {
|
||||
int a=(int)(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
|
||||
int numlines=(int)(w/2);
|
||||
|
||||
for (int j=0; j<numlines; j++) {
|
||||
beginShape();
|
||||
for (int i=0; i<a; i++) {
|
||||
vertex(cosLUT[i]*rad+x,sinLUT[i]*rad+y);
|
||||
}
|
||||
endShape();
|
||||
rad += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw arc line with bars
|
||||
public void arcLineBars(float x,float y,float deg,float rad,float w) {
|
||||
int a = int((min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1)));
|
||||
a /= 4;
|
||||
|
||||
beginShape(QUADS);
|
||||
for (int i=0; i<a; i+=4) {
|
||||
vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
|
||||
vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
|
||||
vertex(cosLUT[i+2]*(rad+w)+x,sinLUT[i+2]*(rad+w)+y);
|
||||
vertex(cosLUT[i+2]*(rad)+x,sinLUT[i+2]*(rad)+y);
|
||||
}
|
||||
endShape();
|
||||
}
|
||||
|
||||
// Draw solid arc
|
||||
public void arc(float x,float y,float deg,float rad,float w) {
|
||||
int a = int(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
|
||||
beginShape(QUAD_STRIP);
|
||||
for (int i = 0; i < a; i++) {
|
||||
vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
|
||||
vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
|
||||
}
|
||||
endShape();
|
||||
}
|
||||
|
||||
void keyPressed() {
|
||||
if (key == 's') {
|
||||
dosave=true;
|
||||
}
|
||||
}
|
||||
|
||||
void mouseReleased() {
|
||||
background(255);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Large Page.
|
||||
*
|
||||
* Saves one frame as a PDF with a size larger
|
||||
* than the screen. When PDF is used as the renderer
|
||||
* (the third parameter of size) the display window
|
||||
* does not open. The file is saved to the sketch folder.
|
||||
* You can open it by "Sketch->Show Sketch Folder."
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(2000, 2000, PDF, "Line.pdf");
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
background(255);
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(200, 0, width/2, height);
|
||||
|
||||
exit(); // Quit the program
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Many PDFs.
|
||||
*
|
||||
* Saves one PDF file each each frame while the mouse is pressed.
|
||||
* When the mouse is released, the PDF creation stops.
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
boolean savePDF = false;
|
||||
|
||||
void setup() {
|
||||
size(600, 600);
|
||||
frameRate(24);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if(savePDF == true) {
|
||||
beginRecord(PDF, "lines" + frameCount + ".pdf");
|
||||
}
|
||||
background(255);
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(mouseX, 0, width-mouseY, height);
|
||||
if(savePDF == true) {
|
||||
endRecord();
|
||||
}
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
savePDF = true;
|
||||
}
|
||||
|
||||
void mouseReleased() {
|
||||
savePDF = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Many Pages.
|
||||
*
|
||||
* Saves a new page into a PDF file each loop through draw().
|
||||
* Pressing the mouse finishes writing the file and exits the program.
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
PGraphicsPDF pdf;
|
||||
|
||||
void setup() {
|
||||
size(600, 600);
|
||||
frameRate(4);
|
||||
pdf = (PGraphicsPDF)beginRecord(PDF, "Lines.pdf");
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(255);
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(mouseX, 0, width-mouseY, height);
|
||||
pdf.nextPage();
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
endRecord();
|
||||
exit();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Mouse Press.
|
||||
*
|
||||
* Saves one PDF of the contents of the display window
|
||||
* each time the mouse is pressed.
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
boolean saveOneFrame = false;
|
||||
|
||||
void setup() {
|
||||
size(600, 600);
|
||||
frameRate(24);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if(saveOneFrame == true) {
|
||||
beginRecord(PDF, "Line.pdf");
|
||||
}
|
||||
|
||||
background(255);
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(mouseX, 0, width-mouseY, height);
|
||||
|
||||
if(saveOneFrame == true) {
|
||||
endRecord();
|
||||
saveOneFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
saveOneFrame = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Multiple Frames.
|
||||
*
|
||||
* Saves one PDF document of many frames drawn to the screen.
|
||||
* Starts the file when the mouse is pressed and end the file
|
||||
* when the mouse is released.
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
void setup() {
|
||||
size(600, 600);
|
||||
frameRate(24);
|
||||
background(255);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(mouseX, 0, width-mouseY, height);
|
||||
}
|
||||
|
||||
void mousePressed() {
|
||||
beginRecord(PDF, "Lines.pdf");
|
||||
background(255);
|
||||
}
|
||||
|
||||
void mouseReleased() {
|
||||
endRecord();
|
||||
background(255);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* One Frame.
|
||||
*
|
||||
* Saves one PDF with the contents of the display window.
|
||||
* Because this example uses beginRecord, the image is shown
|
||||
* on the display window and is saved to the file.
|
||||
*/
|
||||
|
||||
|
||||
import processing.pdf.*;
|
||||
|
||||
size(600, 600);
|
||||
|
||||
beginRecord(PDF, "line.pdf");
|
||||
|
||||
background(255);
|
||||
stroke(0, 20);
|
||||
strokeWeight(20.0);
|
||||
line(200, 0, 400, height);
|
||||
|
||||
endRecord();
|
||||
|
||||
|
||||