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