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 * @param baudRate The baud rate to configure the serial port. 088 * @param port The Serial port to use 089 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 090 * @param parity Select the type of parity checking to use. 091 * @param stopBits The number of stop bits to use as defined by the enum StopBits. 092 */ 093 public SerialPort( 094 final int baudRate, Port port, final int dataBits, Parity parity, StopBits stopBits) { 095 m_portHandle = SerialPortJNI.serialInitializePort((byte) port.value); 096 SerialPortJNI.serialSetBaudRate(m_portHandle, baudRate); 097 SerialPortJNI.serialSetDataBits(m_portHandle, (byte) dataBits); 098 SerialPortJNI.serialSetParity(m_portHandle, (byte) parity.value); 099 SerialPortJNI.serialSetStopBits(m_portHandle, (byte) stopBits.value); 100 101 // Set the default read buffer size to 1 to return bytes immediately 102 setReadBufferSize(1); 103 104 // Set the default timeout to 5 seconds. 105 setTimeout(5.0); 106 107 // Don't wait until the buffer is full to transmit. 108 setWriteBufferMode(WriteBufferMode.kFlushOnAccess); 109 110 disableTermination(); 111 112 HAL.report(tResourceType.kResourceType_SerialPort, port.value + 1); 113 } 114 115 /** 116 * Create an instance of a Serial Port class. Defaults to one stop bit. 117 * 118 * @param baudRate The baud rate to configure the serial port. 119 * @param port The serial port to use. 120 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 121 * @param parity Select the type of parity checking to use. 122 */ 123 public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity) { 124 this(baudRate, port, dataBits, parity, StopBits.kOne); 125 } 126 127 /** 128 * Create an instance of a Serial Port class. Defaults to no parity and one stop bit. 129 * 130 * @param baudRate The baud rate to configure the serial port. 131 * @param port The serial port to use. 132 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 133 */ 134 public SerialPort(final int baudRate, Port port, final int dataBits) { 135 this(baudRate, port, dataBits, Parity.kNone, StopBits.kOne); 136 } 137 138 /** 139 * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop bit. 140 * 141 * @param baudRate The baud rate to configure the serial port. 142 * @param port The serial port to use. 143 */ 144 public SerialPort(final int baudRate, Port port) { 145 this(baudRate, port, 8, Parity.kNone, StopBits.kOne); 146 } 147 148 @Override 149 public void close() { 150 SerialPortJNI.serialClose(m_portHandle); 151 } 152 153 /** 154 * Set the type of flow control to enable on this port. 155 * 156 * <p>By default, flow control is disabled. 157 * 158 * @param flowControl the FlowControl m_value to use 159 */ 160 public void setFlowControl(FlowControl flowControl) { 161 SerialPortJNI.serialSetFlowControl(m_portHandle, (byte) flowControl.value); 162 } 163 164 /** 165 * Enable termination and specify the termination character. 166 * 167 * <p>Termination is currently only implemented for receive. When the terminator is received, the 168 * read() or readString() will return fewer bytes than requested, stopping after the terminator. 169 * 170 * @param terminator The character to use for termination. 171 */ 172 public void enableTermination(char terminator) { 173 SerialPortJNI.serialEnableTermination(m_portHandle, terminator); 174 } 175 176 /** 177 * Enable termination with the default terminator '\n' 178 * 179 * <p>Termination is currently only implemented for receive. When the terminator is received, the 180 * read() or readString() will return fewer bytes than requested, stopping after the terminator. 181 * 182 * <p>The default terminator is '\n' 183 */ 184 public void enableTermination() { 185 enableTermination('\n'); 186 } 187 188 /** Disable termination behavior. */ 189 public void disableTermination() { 190 SerialPortJNI.serialDisableTermination(m_portHandle); 191 } 192 193 /** 194 * Get the number of bytes currently available to read from the serial port. 195 * 196 * @return The number of bytes available to read. 197 */ 198 public int getBytesReceived() { 199 return SerialPortJNI.serialGetBytesReceived(m_portHandle); 200 } 201 202 /** 203 * Read a string out of the buffer. Reads the entire contents of the buffer 204 * 205 * @return The read string 206 */ 207 public String readString() { 208 return readString(getBytesReceived()); 209 } 210 211 /** 212 * Read a string out of the buffer. Reads the entire contents of the buffer 213 * 214 * @param count the number of characters to read into the string 215 * @return The read string 216 */ 217 public String readString(int count) { 218 byte[] out = read(count); 219 return new String(out, 0, out.length, StandardCharsets.US_ASCII); 220 } 221 222 /** 223 * Read raw bytes out of the buffer. 224 * 225 * @param count The maximum number of bytes to read. 226 * @return An array of the read bytes 227 */ 228 public byte[] read(final int count) { 229 byte[] dataReceivedBuffer = new byte[count]; 230 int gotten = SerialPortJNI.serialRead(m_portHandle, dataReceivedBuffer, count); 231 if (gotten == count) { 232 return dataReceivedBuffer; 233 } 234 byte[] retVal = new byte[gotten]; 235 System.arraycopy(dataReceivedBuffer, 0, retVal, 0, gotten); 236 return retVal; 237 } 238 239 /** 240 * Write raw bytes to the serial port. 241 * 242 * @param buffer The buffer of bytes to write. 243 * @param count The maximum number of bytes to write. 244 * @return The number of bytes actually written into the port. 245 */ 246 public int write(byte[] buffer, int count) { 247 if (buffer.length < count) { 248 throw new IllegalArgumentException("buffer is too small, must be at least " + count); 249 } 250 return SerialPortJNI.serialWrite(m_portHandle, buffer, count); 251 } 252 253 /** 254 * Write a string to the serial port. 255 * 256 * @param data The string to write to the serial port. 257 * @return The number of bytes actually written into the port. 258 */ 259 public int writeString(String data) { 260 return write(data.getBytes(StandardCharsets.UTF_8), data.length()); 261 } 262 263 /** 264 * Configure the timeout of the serial m_port. 265 * 266 * <p>This defines the timeout for transactions with the hardware. It will affect reads if less 267 * bytes are available than the read buffer size (defaults to 1) and very large writes. 268 * 269 * @param timeout The number of seconds to wait for I/O. 270 */ 271 public void setTimeout(double timeout) { 272 SerialPortJNI.serialSetTimeout(m_portHandle, timeout); 273 } 274 275 /** 276 * Specify the size of the input buffer. 277 * 278 * <p>Specify the amount of data that can be stored before data from the device is returned to 279 * Read. If you want data that is received to be returned immediately, set this to 1. 280 * 281 * <p>It the buffer is not filled before the read timeout expires, all data that has been received 282 * so far will be returned. 283 * 284 * @param size The read buffer size. 285 */ 286 public void setReadBufferSize(int size) { 287 SerialPortJNI.serialSetReadBufferSize(m_portHandle, size); 288 } 289 290 /** 291 * Specify the size of the output buffer. 292 * 293 * <p>Specify the amount of data that can be stored before being transmitted to the device. 294 * 295 * @param size The write buffer size. 296 */ 297 public void setWriteBufferSize(int size) { 298 SerialPortJNI.serialSetWriteBufferSize(m_portHandle, size); 299 } 300 301 /** 302 * Specify the flushing behavior of the output buffer. 303 * 304 * <p>When set to kFlushOnAccess, data is synchronously written to the serial port after each call 305 * to either print() or write(). 306 * 307 * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer is 308 * full or when flush() is called. 309 * 310 * @param mode The write buffer mode. 311 */ 312 public void setWriteBufferMode(WriteBufferMode mode) { 313 SerialPortJNI.serialSetWriteMode(m_portHandle, (byte) mode.value); 314 } 315 316 /** 317 * Force the output buffer to be written to the port. 318 * 319 * <p>This is used when setWriteBufferMode() is set to kFlushWhenFull to force a flush before the 320 * buffer is full. 321 */ 322 public void flush() { 323 SerialPortJNI.serialFlush(m_portHandle); 324 } 325 326 /** 327 * Reset the serial port driver to a known state. 328 * 329 * <p>Empty the transmit and receive buffers in the device and formatted I/O. 330 */ 331 public void reset() { 332 SerialPortJNI.serialClear(m_portHandle); 333 } 334}