001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. 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
008package edu.wpi.first.wpilibj;
009
010import java.io.UnsupportedEncodingException;
011import java.nio.ByteBuffer;
012
013import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
014import edu.wpi.first.wpilibj.hal.HAL;
015import edu.wpi.first.wpilibj.hal.SerialPortJNI;
016
017/**
018 * Driver for the RS-232 serial port on the roboRIO.
019 *
020 * <p>The current implementation uses the VISA formatted I/O mode. This means that all traffic goes
021 * through the formatted buffers. This allows the intermingled use of print(), readString(), and the
022 * raw buffer accessors read() and write().
023 *
024 * <p>More information can be found in the NI-VISA User Manual here: http://www.ni
025 * .com/pdf/manuals/370423a.pdf and the NI-VISA Programmer's Reference Manual here:
026 * http://www.ni.com/pdf/manuals/370132c.pdf
027 */
028public class SerialPort {
029
030  private byte m_port;
031
032  public enum Port {
033    kOnboard(0), kMXP(1), kUSB(2), kUSB1(2), kUSB2(3);
034
035    @SuppressWarnings("MemberName")
036    public int value;
037
038    private Port(int value) {
039      this.value = value;
040    }
041  }
042
043  /**
044   * Represents the parity to use for serial communications.
045   */
046  public enum Parity {
047    kNone(0), kOdd(1), kEven(2), kMark(3), kSpace(4);
048
049    @SuppressWarnings("MemberName")
050    public final int value;
051
052    private Parity(int value) {
053      this.value = value;
054    }
055  }
056
057  /**
058   * Represents the number of stop bits to use for Serial Communication.
059   */
060  public enum StopBits {
061    kOne(10), kOnePointFive(15), kTwo(20);
062
063    @SuppressWarnings("MemberName")
064    public final int value;
065
066    private StopBits(int value) {
067      this.value = value;
068    }
069  }
070
071  /**
072   * Represents what type of flow control to use for serial communication.
073   */
074  public enum FlowControl {
075    kNone(0), kXonXoff(1), kRtsCts(2), kDtsDsr(4);
076
077    @SuppressWarnings("MemberName")
078    public final int value;
079
080    private FlowControl(int value) {
081      this.value = value;
082    }
083  }
084
085  /**
086   * Represents which type of buffer mode to use when writing to a serial m_port.
087   */
088  public enum WriteBufferMode {
089    kFlushOnAccess(1), kFlushWhenFull(2);
090
091    @SuppressWarnings("MemberName")
092    public final int value;
093
094    private WriteBufferMode(int value) {
095      this.value = value;
096    }
097  }
098
099  /**
100   * Create an instance of a Serial Port class.
101   *
102   * @param baudRate The baud rate to configure the serial port.
103   * @param port     The Serial port to use
104   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
105   * @param parity   Select the type of parity checking to use.
106   * @param stopBits The number of stop bits to use as defined by the enum StopBits.
107   */
108  public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity,
109                    StopBits stopBits) {
110    m_port = (byte) port.value;
111
112    SerialPortJNI.serialInitializePort(m_port);
113    SerialPortJNI.serialSetBaudRate(m_port, baudRate);
114    SerialPortJNI.serialSetDataBits(m_port, (byte) dataBits);
115    SerialPortJNI.serialSetParity(m_port, (byte) parity.value);
116    SerialPortJNI.serialSetStopBits(m_port, (byte) stopBits.value);
117
118    // Set the default read buffer size to 1 to return bytes immediately
119    setReadBufferSize(1);
120
121    // Set the default timeout to 5 seconds.
122    setTimeout(5.0);
123
124    // Don't wait until the buffer is full to transmit.
125    setWriteBufferMode(WriteBufferMode.kFlushOnAccess);
126
127    disableTermination();
128
129    HAL.report(tResourceType.kResourceType_SerialPort, 0);
130  }
131
132  /**
133   * Create an instance of a Serial Port class. Defaults to one stop bit.
134   *
135   * @param baudRate The baud rate to configure the serial port.
136   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
137   * @param parity   Select the type of parity checking to use.
138   */
139  public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity) {
140    this(baudRate, port, dataBits, parity, StopBits.kOne);
141  }
142
143  /**
144   * Create an instance of a Serial Port class. Defaults to no parity and one stop bit.
145   *
146   * @param baudRate The baud rate to configure the serial port.
147   * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
148   */
149  public SerialPort(final int baudRate, Port port, final int dataBits) {
150    this(baudRate, port, dataBits, Parity.kNone, StopBits.kOne);
151  }
152
153  /**
154   * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop
155   * bit.
156   *
157   * @param baudRate The baud rate to configure the serial port.
158   */
159  public SerialPort(final int baudRate, Port port) {
160    this(baudRate, port, 8, Parity.kNone, StopBits.kOne);
161  }
162
163  /**
164   * Destructor.
165   */
166  public void free() {
167    SerialPortJNI.serialClose(m_port);
168  }
169
170  /**
171   * Set the type of flow control to enable on this port.
172   *
173   * <p>By default, flow control is disabled.
174   *
175   * @param flowControl the FlowControl m_value to use
176   */
177  public void setFlowControl(FlowControl flowControl) {
178    SerialPortJNI.serialSetFlowControl(m_port, (byte) flowControl.value);
179  }
180
181  /**
182   * Enable termination and specify the termination character.
183   *
184   * <p>Termination is currently only implemented for receive. When the the terminator is received,
185   * the read() or readString() will return fewer bytes than requested, stopping after the
186   * terminator.
187   *
188   * @param terminator The character to use for termination.
189   */
190  public void enableTermination(char terminator) {
191    SerialPortJNI.serialEnableTermination(m_port, terminator);
192  }
193
194  /**
195   * Enable termination with the default terminator '\n'
196   *
197   * <p>Termination is currently only implemented for receive. When the the terminator is received,
198   * the read() or readString() will return fewer bytes than requested, stopping after the
199   * terminator.
200   *
201   * <p>The default terminator is '\n'
202   */
203  public void enableTermination() {
204    enableTermination('\n');
205  }
206
207  /**
208   * Disable termination behavior.
209   */
210  public void disableTermination() {
211    SerialPortJNI.serialDisableTermination(m_port);
212  }
213
214  /**
215   * Get the number of bytes currently available to read from the serial port.
216   *
217   * @return The number of bytes available to read.
218   */
219  public int getBytesReceived() {
220    return SerialPortJNI.serialGetBytesRecieved(m_port);
221  }
222
223  /**
224   * Read a string out of the buffer. Reads the entire contents of the buffer
225   *
226   * @return The read string
227   */
228  public String readString() {
229    return readString(getBytesReceived());
230  }
231
232  /**
233   * Read a string out of the buffer. Reads the entire contents of the buffer
234   *
235   * @param count the number of characters to read into the string
236   * @return The read string
237   */
238  public String readString(int count) {
239    byte[] out = read(count);
240    try {
241      return new String(out, 0, out.length, "US-ASCII");
242    } catch (UnsupportedEncodingException ex) {
243      ex.printStackTrace();
244      return "";
245    }
246  }
247
248  /**
249   * Read raw bytes out of the buffer.
250   *
251   * @param count The maximum number of bytes to read.
252   * @return An array of the read bytes
253   */
254  public byte[] read(final int count) {
255    ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(count);
256    int gotten = SerialPortJNI.serialRead(m_port, dataReceivedBuffer, count);
257    byte[] retVal = new byte[gotten];
258    dataReceivedBuffer.get(retVal);
259    return retVal;
260  }
261
262  /**
263   * Write raw bytes to the serial port.
264   *
265   * @param buffer The buffer of bytes to write.
266   * @param count  The maximum number of bytes to write.
267   * @return The number of bytes actually written into the port.
268   */
269  public int write(byte[] buffer, int count) {
270    ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(count);
271    dataToSendBuffer.put(buffer, 0, count);
272    return SerialPortJNI.serialWrite(m_port, dataToSendBuffer, count);
273  }
274
275  /**
276   * Write a string to the serial port
277   *
278   * @param data The string to write to the serial port.
279   * @return The number of bytes actually written into the port.
280   */
281  public int writeString(String data) {
282    return write(data.getBytes(), data.length());
283  }
284
285  /**
286   * Configure the timeout of the serial m_port.
287   *
288   * <p>This defines the timeout for transactions with the hardware. It will affect reads if less
289   * bytes are available than the read buffer size (defaults to 1) and very large writes.
290   *
291   * @param timeout The number of seconds to to wait for I/O.
292   */
293  public void setTimeout(double timeout) {
294    SerialPortJNI.serialSetTimeout(m_port, timeout);
295  }
296
297  /**
298   * Specify the size of the input buffer.
299   *
300   * <p>Specify the amount of data that can be stored before data from the device is returned to
301   * Read. If you want data that is received to be returned immediately, set this to 1.
302   *
303   * <p>It the buffer is not filled before the read timeout expires, all data that has been received
304   * so far will be returned.
305   *
306   * @param size The read buffer size.
307   */
308  public void setReadBufferSize(int size) {
309    SerialPortJNI.serialSetReadBufferSize(m_port, size);
310  }
311
312  /**
313   * Specify the size of the output buffer.
314   *
315   * <p>Specify the amount of data that can be stored before being transmitted to the device.
316   *
317   * @param size The write buffer size.
318   */
319  public void setWriteBufferSize(int size) {
320    SerialPortJNI.serialSetWriteBufferSize(m_port, size);
321  }
322
323  /**
324   * Specify the flushing behavior of the output buffer.
325   *
326   * <p>When set to kFlushOnAccess, data is synchronously written to the serial port after each
327   * call to either print() or write().
328   *
329   * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer
330   * is full or when flush() is called.
331   *
332   * @param mode The write buffer mode.
333   */
334  public void setWriteBufferMode(WriteBufferMode mode) {
335    SerialPortJNI.serialSetWriteMode(m_port, (byte) mode.value);
336  }
337
338  /**
339   * Force the output buffer to be written to the port.
340   *
341   * <p>This is used when setWriteBufferMode() is set to kFlushWhenFull to force a flush before the
342   * buffer is full.
343   */
344  public void flush() {
345    SerialPortJNI.serialFlush(m_port);
346  }
347
348  /**
349   * Reset the serial port driver to a known state.
350   *
351   * <p>Empty the transmit and receive buffers in the device and formatted I/O.
352   */
353  public void reset() {
354    SerialPortJNI.serialClear(m_port);
355  }
356}