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