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}