001    /*----------------------------------------------------------------------------*/
002    /* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003    /* Open Source Software - may be modified and shared by FRC teams. The code   */
004    /* must be accompanied by the FIRST BSD license file in the root directory of */
005    /* the project.                                                               */
006    /*----------------------------------------------------------------------------*/
007    
008    package com.sun.squawk.io.j2me.dserror;
009    
010    import com.sun.cldc.jna.Pointer;
011    import java.io.*;
012    import javax.microedition.io.*;
013    import com.sun.squawk.io.*;
014    import edu.wpi.first.wpilibj.communication.FRCControl;
015    
016    /**
017     * This Generic Connection Framework Protocol class writes to the FRC Driver Station error pane.
018     * @author dw29446
019     */
020    public class Protocol extends ConnectionBase implements OutputConnection {
021    
022        protected boolean opened = false;
023    
024        public Protocol() {
025        }
026        
027        /**
028         * Open the connection
029         * @param name       the target for the connection
030         * @param timeouts   a flag to indicate that the called wants
031         *                   timeout exceptions
032         */
033        public Connection open(String protocol, String name, int mode, boolean timeouts)
034                throws IOException {
035            return this;
036        }
037    
038        /**
039         * Returns an output stream for this socket.
040         *
041         * @return     an output stream for writing bytes to this socket.
042         * @exception  IOException  if an I/O error occurs when creating
043         *                          the output stream.
044         */
045        public OutputStream openOutputStream()
046                throws IOException {
047    
048            if (opened) {
049                throw new IOException("Stream already opened");
050            }
051            opened = true;
052            return new DSErrorOutputStream();
053        }
054    }
055    
056    /**
057     * Output stream for the connection
058     */
059    class DSErrorOutputStream extends OutputStream {
060    
061        final static int DEFAULT_BUFFER_SIZE = 512;
062        private Pointer errorBuffer;
063        private int index;
064        private boolean errorOccurred;
065    
066        /**
067         * Constructor
068         */
069        DSErrorOutputStream() {
070            errorBuffer = new Pointer(DEFAULT_BUFFER_SIZE);
071            index = 0;
072        }
073    
074        /**
075         * Writes the specified byte to this output stream.
076         *
077         * @param      b   the <code>byte</code>.
078         * @exception  IOException  if an I/O error occurs. In particular,
079         *             an <code>IOException</code> may be thrown if the
080         *             output stream has been closed.
081         */
082        synchronized public void write(int b)
083                throws IOException {
084            if (errorOccurred) {
085                return;
086            }
087            try {
088                if (errorBuffer == null) {
089                    throw new IllegalStateException("DSErrorOutputStream is closed");
090                }
091    
092                if (index >= errorBuffer.getSize()) {
093                    flush();
094                }
095    
096                if (b == '\n' && index != 0) {
097                    flush(); // appends cr and nl...
098                } else {
099                    errorBuffer.setByte(index++, (byte) b);
100                }
101            } catch (Throwable e) {
102                errorOccurred = true;
103                throw new RuntimeException("Squashing exception in error stream writer: " + e);
104            }
105        }
106    
107    //    public synchronized void write(byte b[], int off, int len) throws IOException {
108    //        if (b == null) {
109    //            throw new NullPointerException();
110    //        } else if ((off < 0) || (off > b.length) || (len < 0) ||
111    //                   ((off + len) > b.length) || ((off + len) < 0)) {
112    //            throw new IndexOutOfBoundsException();
113    //        } else if (len == 0) {
114    //            return;
115    //        }
116    //        for (int i = 0 ; i < len ; i++) {
117    //            write(b[off + i]);
118    //        }
119    //    }
120    
121        /**
122         * Flushes this output stream and forces any buffered output bytes
123         * to be written out. The general contract of <code>flush</code> is
124         * that calling it is an indication that, if any bytes previously
125         * written have been buffered by the implementation of the output
126         * stream, such bytes should immediately be written to their
127         * intended destination.
128         * <p>
129         * The <code>flush</code> method of <code>OutputStream</code> does nothing.
130         *
131         * @exception  IOException  if an I/O error occurs.
132         */
133        public synchronized void flush()
134                throws IOException {
135            if (errorBuffer == null) {
136                throw new IllegalStateException("DSErrorOutputStream is closed");
137            }
138    
139            if (index > 0) {
140                FRCControl.setErrorData(errorBuffer, index, 100);
141                index = 0;
142            }
143        }
144    
145        /**
146         * Close the stream
147         *
148         * @exception  IOException  if an I/O error occurs.
149         */
150        public synchronized void close() {
151            if (errorBuffer != null) {
152                index = 0;
153                errorBuffer.free();
154                errorBuffer = null;
155            }
156        }
157    }
158