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    package edu.wpi.first.wpilibj;
008    
009    import edu.wpi.first.wpilibj.communication.UsageReporting;
010    import edu.wpi.first.wpilibj.visa.Visa;
011    import edu.wpi.first.wpilibj.visa.VisaException;
012    import java.io.UnsupportedEncodingException;
013    
014    /**
015     * Driver for the RS-232 serial port on the cRIO.
016     *
017     * The current implementation uses the VISA formatted I/O mode.  This means that
018     *   all traffic goes through the formatted buffers.  This allows the intermingled
019     *   use of print(), readString(), and the raw buffer accessors read() and write().
020     *
021     * More information can be found in the NI-VISA User Manual here:
022     *   http://www.ni.com/pdf/manuals/370423a.pdf
023     * and the NI-VISA Programmer's Reference Manual here:
024     *   http://www.ni.com/pdf/manuals/370132c.pdf
025     */
026    public class SerialPort {
027    
028        private int m_resourceManagerHandle;
029        private int m_portHandle;
030    
031        /**
032         * Represents the parity to use for serial communications
033         */
034        public static class Parity {
035    
036            /**
037             * The integer value representing this enumeration
038             */
039            public final int value;
040            static final int kNone_val = 0;
041            static final int kOdd_val = 1;
042            static final int kEven_val = 2;
043            static final int kMark_val = 3;
044            static final int kSpace_val = 4;
045            /**
046             * parity: Use no parity
047             */
048            public static final Parity kNone = new Parity(kNone_val);
049            /**
050             * parity: Use odd parity
051             */
052            public static final Parity kOdd = new Parity(kOdd_val);
053            /**
054             * parity: Use even parity
055             */
056            public static final Parity kEven = new Parity(kEven_val);
057            /**
058             * parity: Use mark parity
059             */
060            public static final Parity kMark = new Parity(kMark_val);
061            /**
062             * parity: Use space parity
063             */
064            public static final Parity kSpace = new Parity((kSpace_val));
065    
066            private Parity(int value) {
067                this.value = value;
068            }
069        }
070    
071        /**
072         * Represents the number of stop bits to use for Serial Communication
073         */
074        public static class StopBits {
075    
076            /**
077             * The integer value representing this enumeration
078             */
079            public final int value;
080            static final int kOne_val = 10;
081            static final int kOnePointFive_val = 15;
082            static final int kTwo_val = 20;
083            /**
084             * stopBits: use 1
085             */
086            public static final StopBits kOne = new StopBits(kOne_val);
087            /**
088             * stopBits: use 1.5
089             */
090            public static final StopBits kOnePointFive = new StopBits(kOnePointFive_val);
091            /**
092             * stopBits: use 2
093             */
094            public static final StopBits kTwo = new StopBits(kTwo_val);
095    
096            private StopBits(int value) {
097                this.value = value;
098            }
099        }
100    
101        /**
102         * Represents what type of flow control to use for serial communication
103         */
104        public static class FlowControl {
105    
106            /**
107             * The integer value representing this enumeration
108             */
109            public final int value;
110            static final int kNone_val = 0;
111            static final int kXonXoff_val = 1;
112            static final int kRtsCts_val = 2;
113            static final int kDtrDsr_val = 4;
114            /**
115             * flowControl: use none
116             */
117            public static final FlowControl kNone = new FlowControl(kNone_val);
118            /**
119             * flowcontrol: use on/off
120             */
121            public static final FlowControl kXonXoff = new FlowControl(kXonXoff_val);
122            /**
123             * flowcontrol: use rts cts
124             */
125            public static final FlowControl kRtsCts = new FlowControl(kRtsCts_val);
126            /**
127             * flowcontrol: use dts dsr
128             */
129            public static final FlowControl kDtrDsr = new FlowControl(kDtrDsr_val);
130    
131            private FlowControl(int value) {
132                this.value = value;
133            }
134        }
135    
136        /**
137         * Represents which type of buffer mode to use when writing to a serial port
138         */
139        public static class WriteBufferMode {
140    
141            /**
142             * The integer value representing this enumeration
143             */
144            public final int value;
145            static final int kFlushOnAccess_val = 1;
146            static final int kFlushWhenFull_val = 2;
147            /**
148             * Flush on access
149             */
150            public static final WriteBufferMode kFlushOnAccess = new WriteBufferMode(kFlushOnAccess_val);
151            /**
152             * Flush when full
153             */
154            public static final WriteBufferMode kFlushWhenFull = new WriteBufferMode(kFlushWhenFull_val);
155    
156            private WriteBufferMode(int value) {
157                this.value = value;
158            }
159        }
160    
161        /**
162         * Create an instance of a Serial Port class.
163         *
164         * @param baudRate The baud rate to configure the serial port.  The cRIO-9074 supports up to 230400 Baud.
165         * @param dataBits The number of data bits per transfer.  Valid values are between 5 and 8 bits.
166         * @param parity Select the type of parity checking to use.
167         * @param stopBits The number of stop bits to use as defined by the enum StopBits.
168         */
169        public SerialPort(final int baudRate, final int dataBits, Parity parity, StopBits stopBits) throws VisaException {
170            m_resourceManagerHandle = 0;
171            m_portHandle = 0;
172    
173            m_resourceManagerHandle = Visa.viOpenDefaultRM();
174    
175            m_portHandle = Visa.viOpen(m_resourceManagerHandle, "ASRL1::INSTR", 0, 0);
176    
177            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_BAUD, baudRate);
178    
179            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_DATA_BITS, dataBits);
180    
181            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_PARITY, parity.value);
182    
183            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_STOP_BITS, stopBits.value);
184            
185            // Set the default read buffer size to 1 to return bytes immediately
186            setReadBufferSize(1);
187    
188            // Set the default timeout to 5 seconds.
189            setTimeout(5.0f);
190    
191            // Don't wait until the buffer is full to transmit.
192            setWriteBufferMode(WriteBufferMode.kFlushOnAccess);
193    
194            disableTermination();
195    
196            //viInstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this);
197            //viEnableEvent(m_portHandle, VI_EVENT_IO_COMPLETION, VI_HNDLR, VI_NULL);
198    
199            UsageReporting.report(UsageReporting.kResourceType_SerialPort,0);
200        }
201    
202        /**
203         * Create an instance of a Serial Port class. Defaults to one stop bit.
204         *
205         * @param baudRate The baud rate to configure the serial port.  The cRIO-9074 supports up to 230400 Baud.
206         * @param dataBits The number of data bits per transfer.  Valid values are between 5 and 8 bits.
207         * @param parity Select the type of parity checking to use.
208         */
209        public SerialPort(final int baudRate, final int dataBits, Parity parity) throws VisaException {
210            this(baudRate, dataBits, parity, StopBits.kOne);
211        }
212    
213        /**
214         * Create an instance of a Serial Port class. Defaults to no parity and one
215         * stop bit.
216         *
217         * @param baudRate The baud rate to configure the serial port.  The cRIO-9074 supports up to 230400 Baud.
218         * @param dataBits The number of data bits per transfer.  Valid values are between 5 and 8 bits.
219         */
220        public SerialPort(final int baudRate, final int dataBits) throws VisaException {
221            this(baudRate, dataBits, Parity.kNone, StopBits.kOne);
222        }
223    
224        /**
225         * Create an instance of a Serial Port class. Defaults to 8 databits,
226         * no parity, and one stop bit.
227         *
228         * @param baudRate The baud rate to configure the serial port.  The cRIO-9074 supports up to 230400 Baud.
229         */
230        public SerialPort(final int baudRate) throws VisaException {
231            this(baudRate, 8, Parity.kNone, StopBits.kOne);
232        }
233    
234        /**
235         * Destructor.
236         */
237        public void free() {
238            //viUninstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this);
239            Visa.viClose(m_portHandle);
240            Visa.viClose(m_resourceManagerHandle);
241        }
242    
243        /**
244         * Set the type of flow control to enable on this port.
245         *
246         * By default, flow control is disabled.
247         * @param flowControl
248         */
249        public void setFlowControl(FlowControl flowControl) throws VisaException {
250            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_FLOW_CNTRL, flowControl.value);
251        }
252    
253        /**
254         * Enable termination and specify the termination character.
255         *
256         * Termination is currently only implemented for receive.
257         * When the the terminator is received, the read() or readString() will return
258         *   fewer bytes than requested, stopping after the terminator.
259         *
260         * @param terminator The character to use for termination.
261         */
262        public void enableTermination(char terminator) throws VisaException {
263            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, true);
264            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR, terminator);
265            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_TERMCHAR);
266        }
267    
268        /**
269         * Enable termination and specify the termination character.
270         *
271         * Termination is currently only implemented for receive.
272         * When the the terminator is received, the read() or readString() will return
273         *   fewer bytes than requested, stopping after the terminator.
274         *
275         * The default terminator is '\n'
276         */
277        public void enableTermination() throws VisaException {
278            this.enableTermination('\n');
279        }
280    
281        /**
282         * Disable termination behavior.
283         */
284        public void disableTermination() throws VisaException {
285            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, false);
286            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_NONE);
287        }
288    
289        /**
290         * Get the number of bytes currently available to read from the serial port.
291         *
292         * @return The number of bytes available to read.
293         */
294        public int getBytesReceived() throws VisaException {
295            return Visa.viGetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_AVAIL_NUM);
296        }
297    
298        /**
299         * Output formatted text to the serial port.
300         *
301         * @deprecated use write(string.getBytes()) instead
302         * @bug All pointer-based parameters seem to return an error.
303         *
304         * @param write A string to write
305         */
306        public void print(String write) throws VisaException {
307            Visa.viVPrintf(m_portHandle, write);
308        }
309    
310        /**
311         * Read a string out of the buffer. Reads the entire contents of the buffer
312         *
313         * @return The read string
314         */
315        public String readString() throws VisaException {
316            return readString(getBytesReceived());
317        }
318    
319        /**
320         * Read a string out of the buffer. Reads the entire contents of the buffer
321         *
322         * @param count the number of characters to read into the string
323         * @return The read string
324         */
325        public String readString(int count) throws VisaException {
326            byte[] out = Visa.viBufRead(m_portHandle, count);
327            try {
328                return new String(out, 0, count, "US-ASCII");
329            } catch (UnsupportedEncodingException ex) {
330                ex.printStackTrace();
331                return new String();
332            }
333        }
334    
335        /**
336         * Read raw bytes out of the buffer.
337         *
338         * @param count The maximum number of bytes to read.
339         * @return An array of the read bytes
340         */
341        public byte[] read(final int count) throws VisaException {
342            return Visa.viBufRead(m_portHandle, count);
343        }
344    
345        /**
346         * Write raw bytes to the buffer.
347         *
348         * @param buffer the buffer to read the bytes from.
349         * @param count The maximum number of bytes to write.
350         * @return The number of bytes actually written into the port.
351         */
352        public int write(byte[] buffer, int count) throws VisaException {
353            return Visa.viBufWrite(m_portHandle, buffer, count);
354        }
355    
356        /**
357         * Configure the timeout of the serial port.
358         *
359         * This defines the timeout for transactions with the hardware.
360         * It will affect reads if less bytes are available than the
361         * read buffer size (defaults to 1) and very large writes.
362         *
363         * @param timeout The number of seconds to to wait for I/O.
364         */
365        public void setTimeout(double timeout) throws VisaException {
366            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TMO_VALUE, (int) (timeout * 1e3));
367        }
368        
369        /**
370         * Specify the size of the input buffer.
371         * 
372         * Specify the amount of data that can be stored before data
373         * from the device is returned to Read.  If you want
374         * data that is received to be returned immediately, set this to 1.
375         * 
376         * It the buffer is not filled before the read timeout expires, all
377         * data that has been received so far will be returned.
378         * 
379         * @param size The read buffer size.
380         */
381        void setReadBufferSize(int size) throws VisaException
382        {
383           Visa.viSetBuf(m_portHandle, Visa.VI_READ_BUF, size);
384        }
385        
386        /**
387        * Specify the size of the output buffer.
388        * 
389        * Specify the amount of data that can be stored before being
390        * transmitted to the device.
391        * 
392        * @param size The write buffer size.
393        */
394        void setWriteBufferSize(int size) throws VisaException
395        {
396            Visa.viSetBuf(m_portHandle, Visa.VI_WRITE_BUF, size);
397        }
398    
399        /**
400         * Specify the flushing behavior of the output buffer.
401         *
402         * When set to kFlushOnAccess, data is synchronously written to the serial port
403         *   after each call to either print() or write().
404         *
405         * When set to kFlushWhenFull, data will only be written to the serial port when
406         *   the buffer is full or when flush() is called.
407         *
408         * @param mode The write buffer mode.
409         */
410        public void setWriteBufferMode(WriteBufferMode mode) throws VisaException {
411            Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_WR_BUF_OPER_MODE, mode.value);
412        }
413        
414        /**
415         * Force the output buffer to be written to the port.
416         *
417         * This is used when setWriteBufferMode() is set to kFlushWhenFull to force a
418         * flush before the buffer is full.
419         */
420        public void flush() throws VisaException {
421            Visa.viFlush(m_portHandle, Visa.VI_WRITE_BUF);
422        }
423    
424        /**
425         * Reset the serial port driver to a known state.
426         *
427         * Empty the transmit and receive buffers in the device and formatted I/O.
428         */
429        public void reset() throws VisaException {
430            Visa.viClear(m_portHandle);
431        }
432    }