change folder structure and control files to newest concept

This commit is contained in:
Daniel Stock
2018-09-20 16:38:35 +02:00
parent 224fd33794
commit e25c30f942
2747 changed files with 21 additions and 80 deletions
@@ -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 &rarr; 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="&lt;html&gt;&lt;head&gt;&lt;meta http-equiv='refresh' content='0; url=libraries/io/index.html'&gt;&lt;/head&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;" />
<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);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
@@ -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);
}
}
Binary file not shown.

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;
}
}
@@ -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);
}
@@ -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);
}
Binary file not shown.

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);
}
Binary file not shown.

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;
}
@@ -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));
}
Binary file not shown.

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);
}
@@ -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);
}
}
@@ -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, &param);
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();

Some files were not shown because too many files have changed in this diff Show More