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