001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. 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 package edu.wpi.first.wpilibj; 008 009 import edu.wpi.first.wpilibj.communication.UsageReporting; 010 import edu.wpi.first.wpilibj.visa.Visa; 011 import edu.wpi.first.wpilibj.visa.VisaException; 012 import java.io.UnsupportedEncodingException; 013 014 /** 015 * Driver for the RS-232 serial port on the cRIO. 016 * 017 * The current implementation uses the VISA formatted I/O mode. This means that 018 * all traffic goes through the formatted buffers. This allows the intermingled 019 * use of print(), readString(), and the raw buffer accessors read() and write(). 020 * 021 * More information can be found in the NI-VISA User Manual here: 022 * http://www.ni.com/pdf/manuals/370423a.pdf 023 * and the NI-VISA Programmer's Reference Manual here: 024 * http://www.ni.com/pdf/manuals/370132c.pdf 025 */ 026 public class SerialPort { 027 028 private int m_resourceManagerHandle; 029 private int m_portHandle; 030 031 /** 032 * Represents the parity to use for serial communications 033 */ 034 public static class Parity { 035 036 /** 037 * The integer value representing this enumeration 038 */ 039 public final int value; 040 static final int kNone_val = 0; 041 static final int kOdd_val = 1; 042 static final int kEven_val = 2; 043 static final int kMark_val = 3; 044 static final int kSpace_val = 4; 045 /** 046 * parity: Use no parity 047 */ 048 public static final Parity kNone = new Parity(kNone_val); 049 /** 050 * parity: Use odd parity 051 */ 052 public static final Parity kOdd = new Parity(kOdd_val); 053 /** 054 * parity: Use even parity 055 */ 056 public static final Parity kEven = new Parity(kEven_val); 057 /** 058 * parity: Use mark parity 059 */ 060 public static final Parity kMark = new Parity(kMark_val); 061 /** 062 * parity: Use space parity 063 */ 064 public static final Parity kSpace = new Parity((kSpace_val)); 065 066 private Parity(int value) { 067 this.value = value; 068 } 069 } 070 071 /** 072 * Represents the number of stop bits to use for Serial Communication 073 */ 074 public static class StopBits { 075 076 /** 077 * The integer value representing this enumeration 078 */ 079 public final int value; 080 static final int kOne_val = 10; 081 static final int kOnePointFive_val = 15; 082 static final int kTwo_val = 20; 083 /** 084 * stopBits: use 1 085 */ 086 public static final StopBits kOne = new StopBits(kOne_val); 087 /** 088 * stopBits: use 1.5 089 */ 090 public static final StopBits kOnePointFive = new StopBits(kOnePointFive_val); 091 /** 092 * stopBits: use 2 093 */ 094 public static final StopBits kTwo = new StopBits(kTwo_val); 095 096 private StopBits(int value) { 097 this.value = value; 098 } 099 } 100 101 /** 102 * Represents what type of flow control to use for serial communication 103 */ 104 public static class FlowControl { 105 106 /** 107 * The integer value representing this enumeration 108 */ 109 public final int value; 110 static final int kNone_val = 0; 111 static final int kXonXoff_val = 1; 112 static final int kRtsCts_val = 2; 113 static final int kDtrDsr_val = 4; 114 /** 115 * flowControl: use none 116 */ 117 public static final FlowControl kNone = new FlowControl(kNone_val); 118 /** 119 * flowcontrol: use on/off 120 */ 121 public static final FlowControl kXonXoff = new FlowControl(kXonXoff_val); 122 /** 123 * flowcontrol: use rts cts 124 */ 125 public static final FlowControl kRtsCts = new FlowControl(kRtsCts_val); 126 /** 127 * flowcontrol: use dts dsr 128 */ 129 public static final FlowControl kDtrDsr = new FlowControl(kDtrDsr_val); 130 131 private FlowControl(int value) { 132 this.value = value; 133 } 134 } 135 136 /** 137 * Represents which type of buffer mode to use when writing to a serial port 138 */ 139 public static class WriteBufferMode { 140 141 /** 142 * The integer value representing this enumeration 143 */ 144 public final int value; 145 static final int kFlushOnAccess_val = 1; 146 static final int kFlushWhenFull_val = 2; 147 /** 148 * Flush on access 149 */ 150 public static final WriteBufferMode kFlushOnAccess = new WriteBufferMode(kFlushOnAccess_val); 151 /** 152 * Flush when full 153 */ 154 public static final WriteBufferMode kFlushWhenFull = new WriteBufferMode(kFlushWhenFull_val); 155 156 private WriteBufferMode(int value) { 157 this.value = value; 158 } 159 } 160 161 /** 162 * Create an instance of a Serial Port class. 163 * 164 * @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud. 165 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 166 * @param parity Select the type of parity checking to use. 167 * @param stopBits The number of stop bits to use as defined by the enum StopBits. 168 */ 169 public SerialPort(final int baudRate, final int dataBits, Parity parity, StopBits stopBits) throws VisaException { 170 m_resourceManagerHandle = 0; 171 m_portHandle = 0; 172 173 m_resourceManagerHandle = Visa.viOpenDefaultRM(); 174 175 m_portHandle = Visa.viOpen(m_resourceManagerHandle, "ASRL1::INSTR", 0, 0); 176 177 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_BAUD, baudRate); 178 179 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_DATA_BITS, dataBits); 180 181 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_PARITY, parity.value); 182 183 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_STOP_BITS, stopBits.value); 184 185 // Set the default read buffer size to 1 to return bytes immediately 186 setReadBufferSize(1); 187 188 // Set the default timeout to 5 seconds. 189 setTimeout(5.0f); 190 191 // Don't wait until the buffer is full to transmit. 192 setWriteBufferMode(WriteBufferMode.kFlushOnAccess); 193 194 disableTermination(); 195 196 //viInstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this); 197 //viEnableEvent(m_portHandle, VI_EVENT_IO_COMPLETION, VI_HNDLR, VI_NULL); 198 199 UsageReporting.report(UsageReporting.kResourceType_SerialPort,0); 200 } 201 202 /** 203 * Create an instance of a Serial Port class. Defaults to one stop bit. 204 * 205 * @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud. 206 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 207 * @param parity Select the type of parity checking to use. 208 */ 209 public SerialPort(final int baudRate, final int dataBits, Parity parity) throws VisaException { 210 this(baudRate, dataBits, parity, StopBits.kOne); 211 } 212 213 /** 214 * Create an instance of a Serial Port class. Defaults to no parity and one 215 * stop bit. 216 * 217 * @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud. 218 * @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits. 219 */ 220 public SerialPort(final int baudRate, final int dataBits) throws VisaException { 221 this(baudRate, dataBits, Parity.kNone, StopBits.kOne); 222 } 223 224 /** 225 * Create an instance of a Serial Port class. Defaults to 8 databits, 226 * no parity, and one stop bit. 227 * 228 * @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud. 229 */ 230 public SerialPort(final int baudRate) throws VisaException { 231 this(baudRate, 8, Parity.kNone, StopBits.kOne); 232 } 233 234 /** 235 * Destructor. 236 */ 237 public void free() { 238 //viUninstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this); 239 Visa.viClose(m_portHandle); 240 Visa.viClose(m_resourceManagerHandle); 241 } 242 243 /** 244 * Set the type of flow control to enable on this port. 245 * 246 * By default, flow control is disabled. 247 * @param flowControl 248 */ 249 public void setFlowControl(FlowControl flowControl) throws VisaException { 250 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_FLOW_CNTRL, flowControl.value); 251 } 252 253 /** 254 * Enable termination and specify the termination character. 255 * 256 * Termination is currently only implemented for receive. 257 * When the the terminator is received, the read() or readString() will return 258 * fewer bytes than requested, stopping after the terminator. 259 * 260 * @param terminator The character to use for termination. 261 */ 262 public void enableTermination(char terminator) throws VisaException { 263 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, true); 264 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR, terminator); 265 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_TERMCHAR); 266 } 267 268 /** 269 * Enable termination and specify the termination character. 270 * 271 * Termination is currently only implemented for receive. 272 * When the the terminator is received, the read() or readString() will return 273 * fewer bytes than requested, stopping after the terminator. 274 * 275 * The default terminator is '\n' 276 */ 277 public void enableTermination() throws VisaException { 278 this.enableTermination('\n'); 279 } 280 281 /** 282 * Disable termination behavior. 283 */ 284 public void disableTermination() throws VisaException { 285 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, false); 286 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_NONE); 287 } 288 289 /** 290 * Get the number of bytes currently available to read from the serial port. 291 * 292 * @return The number of bytes available to read. 293 */ 294 public int getBytesReceived() throws VisaException { 295 return Visa.viGetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_AVAIL_NUM); 296 } 297 298 /** 299 * Output formatted text to the serial port. 300 * 301 * @deprecated use write(string.getBytes()) instead 302 * @bug All pointer-based parameters seem to return an error. 303 * 304 * @param write A string to write 305 */ 306 public void print(String write) throws VisaException { 307 Visa.viVPrintf(m_portHandle, write); 308 } 309 310 /** 311 * Read a string out of the buffer. Reads the entire contents of the buffer 312 * 313 * @return The read string 314 */ 315 public String readString() throws VisaException { 316 return readString(getBytesReceived()); 317 } 318 319 /** 320 * Read a string out of the buffer. Reads the entire contents of the buffer 321 * 322 * @param count the number of characters to read into the string 323 * @return The read string 324 */ 325 public String readString(int count) throws VisaException { 326 byte[] out = Visa.viBufRead(m_portHandle, count); 327 try { 328 return new String(out, 0, count, "US-ASCII"); 329 } catch (UnsupportedEncodingException ex) { 330 ex.printStackTrace(); 331 return new String(); 332 } 333 } 334 335 /** 336 * Read raw bytes out of the buffer. 337 * 338 * @param count The maximum number of bytes to read. 339 * @return An array of the read bytes 340 */ 341 public byte[] read(final int count) throws VisaException { 342 return Visa.viBufRead(m_portHandle, count); 343 } 344 345 /** 346 * Write raw bytes to the buffer. 347 * 348 * @param buffer the buffer to read the bytes from. 349 * @param count The maximum number of bytes to write. 350 * @return The number of bytes actually written into the port. 351 */ 352 public int write(byte[] buffer, int count) throws VisaException { 353 return Visa.viBufWrite(m_portHandle, buffer, count); 354 } 355 356 /** 357 * Configure the timeout of the serial port. 358 * 359 * This defines the timeout for transactions with the hardware. 360 * It will affect reads if less bytes are available than the 361 * read buffer size (defaults to 1) and very large writes. 362 * 363 * @param timeout The number of seconds to to wait for I/O. 364 */ 365 public void setTimeout(double timeout) throws VisaException { 366 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TMO_VALUE, (int) (timeout * 1e3)); 367 } 368 369 /** 370 * Specify the size of the input buffer. 371 * 372 * Specify the amount of data that can be stored before data 373 * from the device is returned to Read. If you want 374 * data that is received to be returned immediately, set this to 1. 375 * 376 * It the buffer is not filled before the read timeout expires, all 377 * data that has been received so far will be returned. 378 * 379 * @param size The read buffer size. 380 */ 381 void setReadBufferSize(int size) throws VisaException 382 { 383 Visa.viSetBuf(m_portHandle, Visa.VI_READ_BUF, size); 384 } 385 386 /** 387 * Specify the size of the output buffer. 388 * 389 * Specify the amount of data that can be stored before being 390 * transmitted to the device. 391 * 392 * @param size The write buffer size. 393 */ 394 void setWriteBufferSize(int size) throws VisaException 395 { 396 Visa.viSetBuf(m_portHandle, Visa.VI_WRITE_BUF, size); 397 } 398 399 /** 400 * Specify the flushing behavior of the output buffer. 401 * 402 * When set to kFlushOnAccess, data is synchronously written to the serial port 403 * after each call to either print() or write(). 404 * 405 * When set to kFlushWhenFull, data will only be written to the serial port when 406 * the buffer is full or when flush() is called. 407 * 408 * @param mode The write buffer mode. 409 */ 410 public void setWriteBufferMode(WriteBufferMode mode) throws VisaException { 411 Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_WR_BUF_OPER_MODE, mode.value); 412 } 413 414 /** 415 * Force the output buffer to be written to the port. 416 * 417 * This is used when setWriteBufferMode() is set to kFlushWhenFull to force a 418 * flush before the buffer is full. 419 */ 420 public void flush() throws VisaException { 421 Visa.viFlush(m_portHandle, Visa.VI_WRITE_BUF); 422 } 423 424 /** 425 * Reset the serial port driver to a known state. 426 * 427 * Empty the transmit and receive buffers in the device and formatted I/O. 428 */ 429 public void reset() throws VisaException { 430 Visa.viClear(m_portHandle); 431 } 432 }