Fixed networking performance in OPC server
authorMicah Elizabeth Scott <micah@scanlime.org>
Sat, 29 Mar 2014 19:50:12 +0000 (12:50 -0700)
committerMicah Elizabeth Scott <micah@scanlime.org>
Sat, 29 Mar 2014 19:50:12 +0000 (12:50 -0700)
OpenPixelControl.pde

index 830ba6c1b07a5812ab46b50c740dbc7491b2c8da..0525d9013dce9f71f5bd813ffec078414e486f86 100644 (file)
-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);
         }
     }