/* // here's how to do it with a socket final JStem stem = new jStem(); // or whatever Socket s = new Socket("localhost", 5002); NonBlockingInputStream inputStream = new NonBlockingInputStream(s.getInputStream()); OutputStream outputStream = s.getOutputStream(); ((NonBlockingInputStream)inputStream).registerNonBlockingEvent(new StreamEventListener() { public void streamEvent(InputStream stream) { stem.nonBlockingEvent(); } }); // tell the stream where to get I/O stem.SetStream(inputStream, outputStream); // here's how to do it using the I2C code (cross fingers) final JStem stem = new jStem(); // or whatever NonBlockingInputStream inputStream = new NonBlockingInputStream(new FileInputStream("/dev/brainstem")); OutputStream outputStream = new FileOutputStream("/dev/brainstem"); ((NonBlockingInputStream)inputStream).registerNonBlockingEvent(new StreamEventListener() { public void streamEvent(InputStream stream) { stem.nonBlockingEvent(); } }); // tell the stream where to get I/O stem.SetStream(inputStream, outputStream); */ /* show(); import acroname.*; Brainstem b = new Brainstem(); b.setServo(4,2,160); b.getA2D(4,2); b.getDigital(4,1); */ package acroname; import java.io.*; /** A wrapper for Java's input streams which provides for nonblocking reads and provides stream events to a listener. When you construct a NonBlockingInputStream, a background thread is created which constantly reads from the underlying InputStream and loads the result into a buffer. mark(), reset(), and skip() are presently unsupported.

You can perform blocking reads as usual, but you also have the option of performing nonblocking reads where after some specified timeout after which the read returns even if it has not read fully. If data is immediately available, nonblocking reads will return that data even if it's not everything you need, so you may need to read again. You can further do a blocking available() with a timeout.

If you need it, you can register a StreamEventListener which is notified each time data comes available on the InputStream. This notification will occur from the underlying Thread, so you want to do your read and not block elsewhere at that point. */ public class NonBlockingInputStream extends FilterInputStream { StreamEventListener listener; Object listener_lock = new Object(); public void registerNonBlockingEvent(StreamEventListener listener) { synchronized(listener_lock) { this.listener = listener; } } public NonBlockingInputStream(InputStream in) { this(in, 256, false); } public NonBlockingInputStream(InputStream in, int initialBufferSize, boolean useAvailable) { super(in); this.useAvailable = useAvailable; c = new byte[initialBufferSize]; c2 = new byte[initialBufferSize]; startThread(); } // CAN WE USE AVAILABLE? boolean useAvailable = false; // THE BUFFER byte[] c; // our character buffer byte[] c2; // temporary buffer static final int EMPTY = -1; // indicates nothing there Object c_lock = new Object(); // lock on this to get access to c int length; // how much data is available int offset; // offset into c where data starts // THE THREAD STATE int state = READING; // the current state of the startThread static final int AVAILABLE = 1; // the start thread has made a char available in c and is waiting // to be notified that the char was read by someone static final int READING = 0; // the start thread is reading in another char from I/O and // nothing is available in c Object state_lock = new Object(); // lock on this to get access to state // DID THE THREAD DIE? IOException exception = null; // the thread is fine Object exception_lock = new Object(); // lock on this to get access to exception // THE BACKGROUND READING THREAD public void startThread() { new Thread(new Runnable() { public void run() { while(true) { // at this stage we're in READING mode, so we have control of c. // we try to read in a character, and block until we're successful. try { if (useAvailable) { int i = in.available(); if (i > c2.length) c2 = new byte[i]; } int len = in.read(c2); System.out.println("In "+len+": "); for(int x=0;x 0) System.arraycopy(c2,0,c,0,len); length = len; offset = 0; } System.out.println("Copied"); } catch (IOException e) { synchronized(exception_lock) { exception = e; } // oops, die and kill the stream return; // die } // okay, so we read something into c. // now we let others know who are waiting, and set the mode to // AVAILABLE so they can have a chance to read c. try { synchronized(state_lock) { state = AVAILABLE; state_lock.notify(); } if (length == -1) return; // we're done // we also let a thread know something's available. Of course, if some // other thread just read stuff, this fact is worthless. // Maybe get rid of jStem and make it NonBlockingInputStreamListener or // something. StreamEventListener foo; synchronized(listener_lock) { foo = listener; } if (foo!=null) foo.streamEvent(NonBlockingInputStream.this); // Last we wait until someone has read c and changed things back to // READING so we can go ahead and read something into c again. synchronized(state_lock) { while(state!=READING) state_lock.wait(); } } catch (InterruptedException e) { } } } }).start(); } // waits up to millis for *something* to come available, then returns how much has come available, // or 0 if nothing came available public int available(int millis) throws IOException { try { synchronized(state_lock) { synchronized(exception_lock) { if (exception != null) throw exception; } synchronized(c_lock) { if (state==AVAILABLE) return length == -1 ? 0 : length + (useAvailable ? in.available() : 0); // c's got something in it } if (millis > 0) state_lock.wait(millis); // else wait for a while, maybe something will show up synchronized(exception_lock) { if (exception != null) throw exception; } synchronized(c_lock) { if (state==AVAILABLE) return length == -1 ? 0 : length + (useAvailable ? in.available() : 0); // c's got something it _now_ else return (useAvailable ? in.available() : 0); // nada } } } catch (InterruptedException e) { } return (useAvailable ? in.available() : 0); } byte[] read1 = new byte[1]; // private public int read() throws IOException { synchronized(read1) { while(true) { int len = read(read1,0,1); if (len == -1) return -1; if (len == 1) return read1[0]; // if 0, keep on trying } } } public int readNonBlocking(byte[] buffer, int offset, int len, int millis) throws IOException { int a = available(millis); synchronized(c_lock) { if (length == -1) return -1; } if (a > 0) return read(buffer,offset,len); else return 0; } public int readNonBlocking(byte[] buffer, int millis) throws IOException { return readNonBlocking(buffer,0,buffer.length,millis); } public static final int READ_FAILED = -100; /** Returns a -1 if EOF, and READ_FAILED if nothing was readable in the provided seconds. */ public int readNonBlocking(int millis) throws IOException { synchronized(c_lock) { if (length == -1) return -1; } int a = available(millis); synchronized(c_lock) { if (length == -1) return -1; } if (a > 0) return read(); else return READ_FAILED; } /** Blocking Read */ public int read(byte[] buffer) throws IOException { return read(buffer,0,buffer.length); } /** Blocking Read */ public int read(byte[] buffer, int off, int len) throws IOException { if (buffer==null) throw new IOException("Null buffer"); if (off + len > buffer.length || off < 0 || len <= 0) throw new IOException("Bad offset (" + off + ") or length (" + len + ") for buffer of size " + buffer.length); synchronized(exception_lock) { if (exception != null) throw exception; } try { System.out.println("waiting"); // wait until a character comes available in c synchronized(state_lock) { while(state!=AVAILABLE) state_lock.wait(); } } catch(InterruptedException e) { } synchronized(exception_lock) { if (exception != null) throw exception; if (length == -1) return -1; // EOF // load buffer int l = len; if (l > length) l = length; System.arraycopy(c,offset,buffer,off,l); offset += l; length -= l; System.out.println("Read "+l+": "); for(int x=0;x 0) { if (a > len - l) a = len - l; l += in.read(buffer,off+l,a); // top it off } } synchronized(state_lock) { if (length == 0) // nothing left, block again and let the background have c again { state = READING; state_lock.notify(); } } return l; } } public long skip(long n) throws IOException { throw new IOException("Skip Not Supported"); } /** Same as available(0) */ public int available() throws IOException { return available(0); } public void close() throws IOException { synchronized(exception_lock) { if (exception != null) throw exception; in.close(); } } public synchronized void mark(int readlimit) { } public synchronized void reset() throws IOException { throw new IOException("Mark Not Supported"); } public boolean markSupported() { return in.markSupported(); } }