001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj; 006 007import edu.wpi.first.hal.HAL; 008import edu.wpi.first.hal.SerialPortJNI; 009import java.nio.charset.StandardCharsets; 010 011/** Driver for the serial ports (USB, MXP, Onboard) on the roboRIO. */ 012public class SerialPort implements AutoCloseable { 013 private int m_portHandle; 014 015 /** Serial port. */ 016 public enum Port { 017 /** Onboard serial port on the roboRIO. */ 018 kOnboard(0), 019 /** MXP (roboRIO MXP) serial port. */ 020 kMXP(1), 021 /** USB serial port (same as kUSB1). */ 022 kUSB(2), 023 /** USB serial port 1. */ 024 kUSB1(2), 025 /** USB serial port 2. */ 026 kUSB2(3); 027 028 /** Port value. */ 029 public final int value; 030 031 Port(int value) { 032 this.value = value; 033 } 034 } 035 036 /** Represents the parity to use for serial communications. */ 037 public enum Parity { 038 /** No parity. */ 039 kNone(0), 040 /** Odd parity. */ 041 kOdd(1), 042 /** Even parity. */ 043 kEven(2), 044 /** Parity bit always on. */ 045 kMark(3), 046 /** Parity bit always off. */ 047 kSpace(4); 048 049 /** Parity value. */ 050 public final int value; 051 052 Parity(int value) { 053 this.value = value; 054 } 055 } 056 057 /** Represents the number of stop bits to use for Serial Communication. */ 058 public enum StopBits { 059 /** One stop bit. */ 060 kOne(10), 061 /** One and a half stop bits. */ 062 kOnePointFive(15), 063 /** Two stop bits. */ 064 kTwo(20); 065 066 /** StopBits value. */ 067 public final int value; 068 069 StopBits(int value) { 070 this.value = value; 071 } 072 } 073 074 /** Represents what type of flow control to use for serial communication. */ 075 public enum FlowControl { 076 /** No flow control. */ 077 kNone(0), 078 /** XON/XOFF flow control. */ 079 kXonXoff(1), 080 /** RTS/CTS flow control. */ 081 kRtsCts(2), 082 /** DTS/DSR flow control. */ 083 kDtsDsr(4); 084 085 /** FlowControl value. */ 086 public final int value; 087 088 FlowControl(int value) { 089 this.value = value; 090 } 091 } 092 093 /** Represents which type of buffer mode to use when writing to a serial port. */ 094 public enum WriteBufferMode { 095 /** Flush the buffer on each access. */ 096 kFlushOnAccess(1), 097 /** Flush the buffer when it is full. */ 098 kFlushWhenFull(2); 099 100 /** WriteBufferMode value. */ 101 public final int value; 102 103 WriteBufferMode(int value) { 104 this.value = value; 105 } 106 } 107 108 /** 109 * Create an instance of a Serial Port class. 110 * 111 * @param baudRate The baud rate to configure the serial port. 112 * @param port The Serial port to use 113 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 114 * @param parity Select the type of parity checking to use. 115 * @param stopBits The number of stop bits to use as defined by the enum StopBits. 116 */ 117 public SerialPort( 118 final int baudRate, Port port, final int dataBits, Parity parity, StopBits stopBits) { 119 m_portHandle = SerialPortJNI.serialInitializePort((byte) port.value); 120 SerialPortJNI.serialSetBaudRate(m_portHandle, baudRate); 121 SerialPortJNI.serialSetDataBits(m_portHandle, (byte) dataBits); 122 SerialPortJNI.serialSetParity(m_portHandle, (byte) parity.value); 123 SerialPortJNI.serialSetStopBits(m_portHandle, (byte) stopBits.value); 124 125 // Set the default read buffer size to 1 to return bytes immediately 126 setReadBufferSize(1); 127 128 // Set the default timeout to 5 seconds. 129 setTimeout(5.0); 130 131 // Don't wait until the buffer is full to transmit. 132 setWriteBufferMode(WriteBufferMode.kFlushOnAccess); 133 134 disableTermination(); 135 136 HAL.reportUsage("SerialPort", port.value, ""); 137 } 138 139 /** 140 * Create an instance of a Serial Port class. Defaults to one stop bit. 141 * 142 * @param baudRate The baud rate to configure the serial port. 143 * @param port The serial port to use. 144 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 145 * @param parity Select the type of parity checking to use. 146 */ 147 public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity) { 148 this(baudRate, port, dataBits, parity, StopBits.kOne); 149 } 150 151 /** 152 * Create an instance of a Serial Port class. Defaults to no parity and one stop bit. 153 * 154 * @param baudRate The baud rate to configure the serial port. 155 * @param port The serial port to use. 156 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 157 */ 158 public SerialPort(final int baudRate, Port port, final int dataBits) { 159 this(baudRate, port, dataBits, Parity.kNone, StopBits.kOne); 160 } 161 162 /** 163 * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop bit. 164 * 165 * @param baudRate The baud rate to configure the serial port. 166 * @param port The serial port to use. 167 */ 168 public SerialPort(final int baudRate, Port port) { 169 this(baudRate, port, 8, Parity.kNone, StopBits.kOne); 170 } 171 172 @Override 173 public void close() { 174 SerialPortJNI.serialClose(m_portHandle); 175 } 176 177 /** 178 * Set the type of flow control to enable on this port. 179 * 180 * <p>By default, flow control is disabled. 181 * 182 * @param flowControl the FlowControl m_value to use 183 */ 184 public void setFlowControl(FlowControl flowControl) { 185 SerialPortJNI.serialSetFlowControl(m_portHandle, (byte) flowControl.value); 186 } 187 188 /** 189 * Enable termination and specify the termination character. 190 * 191 * <p>Termination is currently only implemented for receive. When the terminator is received, the 192 * read() or readString() will return fewer bytes than requested, stopping after the terminator. 193 * 194 * @param terminator The character to use for termination. 195 */ 196 public void enableTermination(char terminator) { 197 SerialPortJNI.serialEnableTermination(m_portHandle, terminator); 198 } 199 200 /** 201 * Enable termination with the default terminator '\n' 202 * 203 * <p>Termination is currently only implemented for receive. When the terminator is received, the 204 * read() or readString() will return fewer bytes than requested, stopping after the terminator. 205 * 206 * <p>The default terminator is '\n' 207 */ 208 public void enableTermination() { 209 enableTermination('\n'); 210 } 211 212 /** Disable termination behavior. */ 213 public final void disableTermination() { 214 SerialPortJNI.serialDisableTermination(m_portHandle); 215 } 216 217 /** 218 * Get the number of bytes currently available to read from the serial port. 219 * 220 * @return The number of bytes available to read. 221 */ 222 public int getBytesReceived() { 223 return SerialPortJNI.serialGetBytesReceived(m_portHandle); 224 } 225 226 /** 227 * Read a string out of the buffer. Reads the entire contents of the buffer 228 * 229 * @return The read string 230 */ 231 public String readString() { 232 return readString(getBytesReceived()); 233 } 234 235 /** 236 * Read a string out of the buffer. Reads the entire contents of the buffer 237 * 238 * @param count the number of characters to read into the string 239 * @return The read string 240 */ 241 public String readString(int count) { 242 byte[] out = read(count); 243 return new String(out, StandardCharsets.US_ASCII); 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_portHandle, 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_portHandle, 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(StandardCharsets.UTF_8), 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 wait for I/O. 294 */ 295 public final void setTimeout(double timeout) { 296 SerialPortJNI.serialSetTimeout(m_portHandle, 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 final void setReadBufferSize(int size) { 311 SerialPortJNI.serialSetReadBufferSize(m_portHandle, 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_portHandle, 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 call 329 * to either print() or write(). 330 * 331 * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer is 332 * full or when flush() is called. 333 * 334 * @param mode The write buffer mode. 335 */ 336 public final void setWriteBufferMode(WriteBufferMode mode) { 337 SerialPortJNI.serialSetWriteMode(m_portHandle, (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_portHandle); 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_portHandle); 357 } 358}