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 }