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