--- /dev/null
+package lejos.rcxcomm;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+\r
+/** RCXAbstractPort provides an interface similar to java.net.Socket\r
+ * Adapted from original code created by the LEGO3 Team at DTU-IAU\r
+ * RCXAbstractPort implements input and output stream handling and input\r
+ * buffering. It uses a packet handler for sending and receivng packets.\r
+ * This version is abstract because it has no packet handler defined.\r
+ * Specific versions of RCXAbstractPort override the constructor and\r
+ * set up the packet handler to use a specific protocol stack. \r
+ * @author Brian Bagnall\r
+ * @author Lawrie Griffiths\r
+ */\r
+public abstract class RCXAbstractPort {\r
+\r
+ private boolean portOpen = true;\r
+ private Listener listener;\r
+ private int timeOut = 0;\r
+\r
+ private RCXInputStream rcxin;\r
+ private RCXOutputStream rcxout;\r
+ protected PacketHandler packetHandler;\r
+\r
+ /**\r
+ * Constructor for the RCXAbstractPort.\r
+ * Opens the port, and sets the protocol packet handler.\r
+ * @param handler the packet handler\r
+ */\r
+ public RCXAbstractPort(PacketHandler handler) throws IOException {\r
+ packetHandler = handler;\r
+ rcxin = new RCXInputStream(this);\r
+ rcxout = new RCXOutputStream(packetHandler);\r
+ listener = new Listener();\r
+ listener.setDaemon(true);\r
+ listener.start();\r
+ }\r
+\r
+ /** Returns an input stream for this RCXPort.\r
+ * @return an input stream for reading bytes from this RCXPort.\r
+ */\r
+ public InputStream getInputStream() {\r
+ return (InputStream) rcxin;\r
+ }\r
+\r
+ /** Returns an output stream for this RCXPort.\r
+ * @return an output stream for writing bytes to this RCXPort.\r
+ */\r
+ public OutputStream getOutputStream() {\r
+ return (OutputStream) rcxout;\r
+ }\r
+\r
+ /**\r
+ * Resets sequence numbers for this port \r
+ */\r
+ public void reset() {\r
+ packetHandler.reset();\r
+ }\r
+\r
+ /** Closes this RCXPort, stopping the Listener thread.\r
+ */\r
+ public void close() {\r
+ portOpen = false;\r
+ }\r
+\r
+ /** Getter for property timeOut.\r
+ * @return Value of property timeOut.\r
+ */\r
+ public int getTimeOut() {\r
+ return timeOut;\r
+ }\r
+\r
+ /** Setter for property timeOut.\r
+ * @param timeOut New value of property timeOut.\r
+ */\r
+ public void setTimeOut(int timeOut) {\r
+ this.timeOut = timeOut;\r
+ }\r
+\r
+ private byte [] inPacket = new byte[2];\r
+\r
+ /** Listener class runs a thread that reads and buffers bytes.\r
+ * Allows a maximum of two bytes in a packet.\r
+ */\r
+ private class Listener extends Thread {\r
+ public void run() {\r
+ while (portOpen) {\r
+ if (packetHandler.isPacketAvailable()) {\r
+ int r = packetHandler.receivePacket(inPacket);\r
+ for(int i=0;i<r;i++) rcxin.add(inPacket[i]);\r
+ }\r
+ try {\r
+ Thread.sleep(10);\r
+ } catch (InterruptedException iE) { }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Hidden inner class extending InputStream. \r
+ */\r
+ private class RCXInputStream extends InputStream {\r
+\r
+ /** The default buffer size for the InputStream\r
+ */\r
+ public static final int bufferSize = 32;\r
+ private byte[] buffer = new byte[bufferSize];\r
+ private int current = 0, last = 0;\r
+ private RCXAbstractPort dataPort;\r
+ private IOException ioe = new IOException();\r
+\r
+ /** Creates new RCXInputStream\r
+ * @param port The RCXAbstractPort which should deliver data for to this InputStream\r
+ */\r
+ public RCXInputStream(RCXAbstractPort port) {\r
+ dataPort = port;\r
+ }\r
+\r
+ /** Checks if there is any data avaliable on the InputStream\r
+ * @throws IOException is never thrown\r
+ * @return The number of bytes avaliable on the InputStream\r
+ */\r
+ public int available() throws IOException {\r
+ if (last < current)\r
+ return bufferSize-(current-last);\r
+ else\r
+ return last-current;\r
+ }\r
+\r
+ /** Read a single byte from the InputStream. Returns value as\r
+ * an int value between 0 and 255.\r
+ * @throws IOException is thrown when the read is timed out\r
+ * @return A data byte from the stream\r
+ */\r
+ public synchronized int read() throws IOException {\r
+ int time1 = (int)System.currentTimeMillis();\r
+ int timeOut = dataPort.getTimeOut();\r
+ while (available() == 0) {\r
+ if (timeOut != 0 && ((int)System.currentTimeMillis()-time1 > timeOut)) {\r
+ throw ioe;\r
+ }\r
+ try {\r
+ Thread.sleep(10);\r
+ } catch (InterruptedException iE) { }\r
+ }\r
+\r
+ synchronized (buffer) {\r
+ int b = buffer[current++];\r
+ if (current == bufferSize)\r
+ current = 0;\r
+\r
+ if(b < 0) b = b + 256;\r
+ return b;\r
+ }\r
+ }\r
+\r
+ /** Add a data byte to the stream\r
+ * This method should only be called by the RCXPort that\r
+ * created the RCXInputStream\r
+ * @param b The data byte\r
+ */\r
+ void add(byte b) {\r
+ synchronized (buffer) {\r
+ buffer[last++] = b;\r
+ if (last == bufferSize)\r
+ last = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ /** Hidden inner class extending OutputStream. \r
+ */\r
+ private class RCXOutputStream extends OutputStream {\r
+\r
+ private PacketHandler packetHandler;\r
+ private IOException ioe = new IOException();\r
+\r
+ /** Creates new RCXOutputStream\r
+ * @param handler the packet handler used to send data\r
+ */\r
+ public RCXOutputStream(PacketHandler handler) {\r
+ packetHandler = handler;\r
+ }\r
+\r
+ private byte [] bytePacket = new byte[1];\r
+\r
+ /** Write a byte to the OutputStream.\r
+ * @param b The byte.\r
+ * @throws IOException if the byte could not be written to the stream\r
+ */\r
+ public synchronized void write(int b) throws IOException {\r
+ bytePacket[0] = (byte) b;\r
+ if (!packetHandler.sendPacket(bytePacket,1)) throw ioe;\r
+ }\r
+ }\r
+}\r
+\r
+\r