-import processing.net.*;
+
+import java.io.*;
+import java.net.*;
// Server for Open Pixel Control patterns (http://openpixelcontrol.org/)
-class OpenPixelControl extends SCPattern {
+class OpenPixelControl extends SCPattern implements Runnable {
int port = 7890;
-
- Server server;
+ Thread thread;
+ ServerSocket server;
byte[] buffer;
int bufferedByteCount;
public OpenPixelControl(LX lx, PApplet parent) {
super(lx);
- server = new Server(parent, port);
- println("Listening for Open Pixel Control data on port " + port);
+ parent.registerMethod("dispose", this);
+
+ // Save a JSON layout file that some Open Pixel Control clients can use
+ writeMappingFile("openpixelcontrol-layout.json");
// Buffer space for two frames, worst case
buffer = new byte[0x10004 * 2];
bufferedByteCount = 0;
-
- // Save a JSON layout file that some Open Pixel Control clients can use
- writeMappingFile("openpixelcontrol-layout.json");
}
- public void run(double deltaMs) {
- readFromClient();
+ public void dispose() {
+ thread = null;
+ if (server != null) {
+ try {
+ server.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ server = null;
+ }
}
- void readFromClient() {
- Client client = server.available();
-
- if (client == null) {
- // No client; flush any stored partial frames
- bufferedByteCount = 0;
- return;
- }
+ public void run() {
+ // Thread run function; handle OPC traffic.
+ while (Thread.currentThread() == thread) {
+
+ try {
+ Socket cli = server.accept();
+ InputStream input = cli.getInputStream();
+ bufferedByteCount = 0;
+
+ while (Thread.currentThread() == thread) {
+
+ int r = input.read(buffer, bufferedByteCount, buffer.length - bufferedByteCount);
+ if (r <= 0) {
+ break;
+ }
+ bufferedByteCount += r;
+
+ // Extract OPC packets from buffer
+ int offset = 0;
+ while (bufferedByteCount - offset >= 4) {
+ int channel = buffer[offset + 0] & 0xFF;
+ int command = buffer[offset + 1] & 0xFF;
+ int length = ((buffer[offset + 2] & 0xFF) << 8) | (buffer[offset + 3] & 0xFF);
+
+ if (bufferedByteCount - offset < length + 4) {
+ // Not enough data for a full packet yet
+ break;
+ }
+
+ // Handle the packet in-place
+ offset += 4;
+ opcPacket(channel, command, offset, length);
+ offset += length;
+ }
+
+ // If we didn't use the whole buffer, save remainder for later
+ bufferedByteCount -= offset;
+ arrayCopy(buffer, offset, buffer, 0, bufferedByteCount);
+ }
- while (true) {
- int available = client.available();
- if (available <= 0) {
- return;
- }
+ cli.close();
- if (bufferedByteCount == 0) {
- // Read directly to buffer
- bufferedByteCount = client.readBytes(buffer);
- } else {
- // Append to an earlier partial frame
- byte[] additional = new byte[buffer.length - bufferedByteCount];
- int additionalLength = client.readBytes(additional);
- arrayCopy(additional, 0, buffer, bufferedByteCount, additionalLength);
- bufferedByteCount += additionalLength;
+ } catch (IOException e) {
+ e.printStackTrace();
}
+ }
+ }
- // Extract OPC packets from buffer
- int offset = 0;
- while (bufferedByteCount - offset >= 4) {
- int channel = buffer[offset + 0] & 0xFF;
- int command = buffer[offset + 1] & 0xFF;
- int length = ((buffer[offset + 2] & 0xFF) << 8) | (buffer[offset + 3] & 0xFF);
-
- if (bufferedByteCount - offset < length + 4) {
- // Not enough data for a full packet yet
- break;
- }
-
- // Handle the packet in-place
- offset += 4;
- opcPacket(channel, command, offset, length);
- offset += length;
+ public void run(double deltaMs) {
+ // SCPattern run function; nothing to do except start our thread the first time.
+
+ if (server == null) {
+ try {
+ server = new ServerSocket(this.port);
+ thread = new Thread(this);
+ thread.start();
+ println("Listening for Open Pixel Control data on port " + port);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ thread = null;
}
-
- // If we didn't use the whole buffer, save remainder for later
- bufferedByteCount -= offset;
- arrayCopy(buffer, offset, buffer, 0, bufferedByteCount);
}
}