View Javadoc
1 /*** 2 * SerialConnection.java 3 * 4 * Copyright (c) 2003, Raben Systems, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * Neither the name of Raben Systems, Inc. nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package com.raben.telescope.comm; 34 import javax.comm.SerialPortEventListener; 35 import javax.comm.CommPortOwnershipListener; 36 import javax.comm.CommPortIdentifier; 37 import javax.comm.SerialPort; 38 import javax.comm.NoSuchPortException; 39 import javax.comm.SerialPortEvent; 40 import javax.comm.PortInUseException; 41 import javax.comm.UnsupportedCommOperationException; 42 import java.io.OutputStream; 43 import java.io.InputStream; 44 import java.io.IOException; 45 import java.util.TooManyListenersException; 46 import java.util.LinkedList; 47 import java.util.ArrayList; 48 import java.util.Enumeration; 49 /*** 50 * A class to handle communications with a serial connection 51 * @author Vern Raben 52 * @version $Revision: 1.1.1.1 $ $Date: 2003/06/13 04:51:09 $ 53 */ 54 public class SerialConnection implements SerialPortEventListener, 55 CommPortOwnershipListener { 56 /*** Output stream for communications */ 57 private OutputStream os; 58 59 /*** Input stream for communications */ 60 private InputStream is; 61 62 /*** Communications port id */ 63 private CommPortIdentifier portId; 64 65 /*** Serial port */ 66 private SerialPort serialPort; 67 68 /*** flag to indicate whehter comm port is open */ 69 private boolean open = false; 70 71 /*** Name of the communications port */ 72 private String portName = "COM1"; 73 74 /*** Baud rate of connection */ 75 private int baudRate = 9600; 76 77 /*** Number of data bits */ 78 private int databits = SerialPort.DATABITS_8; 79 80 /*** Number of stop bits */ 81 private int stopbits = SerialPort.STOPBITS_1; 82 83 /*** Parity */ 84 private int parity = SerialPort.PARITY_NONE; 85 86 /*** Flow control */ 87 private int flowControl = SerialPort.FLOWCONTROL_NONE 88 | SerialPort.FLOWCONTROL_NONE; 89 90 /*** Queue for receiving characters from comm port */ 91 private MessageQueue messageQueue = new MessageQueue(); 92 93 /*** Buffer for receiving chars from comm port */ 94 private StringBuffer inputBuffer = new StringBuffer(); 95 96 /*** Debug flag */ 97 private boolean debug = false; 98 99 /*** 100 * Create a SerialConnection using default settings of 101 * 8 bits, 9600 baud, no parity, no flow control, and 1 stop bit on 102 * port named COM1 . 103 */ 104 public SerialConnection() { 105 } 106 107 108 /*** 109 * Open a serial connection and IO streams using the current parameters 110 * @exception IOException may occur 111 */ 112 public void openConnection() throws IOException { 113 114 // Obtain a port identifier 115 try { 116 portId = 117 CommPortIdentifier.getPortIdentifier(getPortName()); 118 } catch (NoSuchPortException e) { 119 throw new IOException(e.getMessage()); 120 } 121 122 // Open the port 123 try { 124 serialPort = (SerialPort) portId.open("Telescope Connection", 125 30000); 126 } catch (PortInUseException e) { 127 throw new IOException(e.getMessage()); 128 } 129 130 // Set serial port connection parameters 131 try { 132 setSerialPortConnectionParameters(); 133 os = serialPort.getOutputStream(); 134 is = serialPort.getInputStream(); 135 os.flush(); 136 } catch (IOException e) { 137 serialPort.close(); 138 throw e; 139 } 140 141 // Add this object as an event listener 142 try { 143 serialPort.addEventListener(this); 144 } catch (TooManyListenersException e) { 145 serialPort.close(); 146 throw new IOException("Too many listeners:" + e.getMessage()); 147 } 148 149 // Notify when data is available 150 serialPort.notifyOnDataAvailable(true); 151 152 // Enable receive timeout 153 try { 154 serialPort.enableReceiveTimeout(30); 155 } catch (UnsupportedCommOperationException e) { 156 // Ignore 157 } 158 // Add ownership listener to close connection (to prevent lockout 159 // if program hangs) 160 portId.addPortOwnershipListener(this); 161 open = true; 162 163 } 164 165 /*** 166 * Set the serial port connection parameters 167 * @throws IOException may occur 168 */ 169 private void setSerialPortConnectionParameters() throws IOException { 170 171 // Set serial connection parameters 172 try { 173 serialPort.setSerialPortParams(getBaudRate(), getDatabits(), 174 getStopbits(), getParity()); 175 } catch (UnsupportedCommOperationException e) { 176 throw new IOException("Unsupported serial operation:" 177 + e.getMessage()); 178 } 179 180 // Set flow control. 181 try { 182 serialPort.setFlowControlMode(getFlowControl()); 183 } catch (UnsupportedCommOperationException e) { 184 throw new IOException("Unsupported flow control mode:" 185 + e.getMessage()); 186 } 187 } 188 189 /*** 190 Close the port and clean up associated elements. 191 */ 192 public void closeConnection() { 193 194 // If port is already closed just return. 195 if (!open) { 196 return; 197 } 198 199 200 // Close streams if serialPort not null 201 if (serialPort != null) { 202 try { 203 os.close(); 204 is.close(); 205 } catch (IOException e) { 206 System.err.println(e); 207 } 208 209 // Close the port. 210 serialPort.close(); 211 212 // Remove the ownership listener. 213 portId.removePortOwnershipListener(this); 214 } 215 216 open = false; 217 } 218 219 220 /*** 221 * Check if the serial port is open 222 * @return true if port is open, false if port is closed. 223 */ 224 public boolean isOpen() { 225 return open; 226 } 227 228 /*** 229 * Handle Serial Port Events. 230 * @param evt SerialPortEvent 231 */ 232 public void serialEvent(SerialPortEvent evt) { 233 int newData = 0; 234 235 // Determine type of event. 236 switch (evt.getEventType()) { 237 238 // Read data until -1 is returned 239 case SerialPortEvent.DATA_AVAILABLE: 240 while (newData != -1) { 241 try { 242 newData = is.read(); 243 if (newData == -1) { 244 break; 245 } 246 247 inputBuffer.append((char) newData); 248 249 if (newData == '#') { 250 char[] chars = new char[inputBuffer.length()]; 251 inputBuffer.getChars(0, inputBuffer.length(), 252 chars, 0); 253 messageQueue.addChars(chars); 254 inputBuffer.delete(0, inputBuffer.length()); 255 } 256 257 258 } catch (IOException e) { 259 System.err.println(e); 260 return; 261 } 262 } 263 264 break; 265 } 266 267 } 268 269 /*** 270 * Handle ownership change event. 271 * When PORT_OWNERSHIP_REQUESTED event is 272 * received, close the connection. 273 * @param type Type of owernership event 274 */ 275 public void ownershipChange(int type) { 276 if (type == CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED) { 277 closeConnection(); 278 } 279 } 280 281 282 /*** 283 * Send an array of chars to the serial connection 284 * @param chars Array of chars 285 * @exception IOException may occur 286 */ 287 public void sendChars(char[] chars) throws IOException { 288 289 if ((chars != null) && (isOpen())) { 290 byte[] bytes = new byte[chars.length]; 291 292 for (int i = 0; i < chars.length; i++) { 293 bytes[i] = (byte) chars[i]; 294 } 295 296 if (isDebug()) { 297 System.out.println("SerialConnection.sendChars:" 298 + displayCharArrayAsHexString(chars)); 299 } 300 301 os.write(bytes); 302 os.flush(); 303 } 304 } 305 306 /*** 307 * Send string to the serial connection 308 * @param str The string to send 309 * @throws IOException may occur 310 */ 311 public void sendString(String str) throws IOException { 312 if ((str != null) && (str.length() > 0) && (isOpen())) { 313 char[] chars = new char[80]; 314 str.getChars(0, str.length(), chars, 0); 315 316 if (isDebug()) { 317 System.out.println("SerialConnection.sendString=" + str); 318 } 319 320 os.write(str.getBytes()); 321 os.flush(); 322 323 } 324 } 325 326 /*** 327 * Receive String from serial connection 328 * @return String 329 */ 330 public String receiveString() { 331 332 if (isOpen()) { 333 int count = 0; 334 335 while ((count < 10) && (messageQueue.isEmpty())) { 336 if (count > 0) { 337 System.out.println(getPortName() + ": waiting:" + count); 338 } 339 340 count++; 341 try { 342 Thread.sleep(1000L); 343 } catch (InterruptedException e) { 344 // Ignore 345 } 346 } 347 } 348 349 if (isDebug()) { 350 String response = messageQueue.getMessage(); 351 System.out.println("SerialConnection.receiveString=" + response); 352 return response; 353 } 354 355 return messageQueue.getMessage(); 356 } 357 358 /*** 359 * Receive character array from serial connection 360 * @return char[] 361 */ 362 public char[] receiveChars() { 363 364 if (isOpen()) { 365 int count = 0; 366 367 while ((count < 10) && (messageQueue.isEmpty())) { 368 if (count > 0) { 369 System.out.println(getPortName() + ": waiting:" + count); 370 } 371 372 count++; 373 try { 374 Thread.sleep(1000L); 375 } catch (InterruptedException e) { 376 // Ignore 377 378 } 379 } 380 } 381 382 if (isDebug()) { 383 char[] response = messageQueue.getChars(); 384 System.out.println("SerialConnection.receiveChars:" 385 + displayCharArrayAsHexString(response)); 386 return response; 387 } 388 389 return messageQueue.getChars(); 390 } 391 392 /*** 393 * Set name of port to open 394 * @param portName (example for MS Windows COM1 or COM2) 395 */ 396 public void setPortName(String portName) { 397 this.portName = portName; 398 } 399 400 /*** 401 * Get the port name being used by this connection 402 * @return Current name of the port 403 */ 404 public String getPortName() { 405 return this.portName; 406 } 407 408 409 /*** 410 * Set stop bits. 411 * @param stopbits New stop bits setting. 412 */ 413 public void setStopbits(int stopbits) { 414 this.stopbits = stopbits; 415 } 416 417 /*** 418 * Get stop bits 419 * @return Current stop bits. 420 */ 421 public int getStopbits() { 422 return this.stopbits; 423 } 424 425 /*** 426 * Set parity 427 * @param parity New parity setting. 428 */ 429 public void setParity(int parity) { 430 this.parity = parity; 431 } 432 433 /*** 434 * Get current parity setting 435 * @return parity settting 436 */ 437 public int getParity() { 438 return this.parity; 439 } 440 441 /*** 442 * Get baud rate 443 * @return Current baud rate. 444 */ 445 public int getBaudRate() { 446 return this.baudRate; 447 } 448 449 /*** 450 * Set baud rate. 451 * @param baudRate New baud rate (9600 is default) 452 */ 453 public void setBaudRate(int baudRate) { 454 this.baudRate = baudRate; 455 } 456 457 /*** 458 * Get data bits 459 * @return Current data bits setting. 460 */ 461 public int getDatabits() { 462 return this.databits; 463 } 464 465 /*** 466 * Set new data bits. 467 * @param databits New data bits setting. 468 */ 469 public void setDatabits(int databits) { 470 this.databits = databits; 471 } 472 473 /*** 474 * Set flow control 475 476 * Formed by "or-ing" both "in" and "out" flow control settings. 477 * The efault is SerialPort.FLOWCONTROL_NONE | SerialPort.FLOWCONTROL_NONE. 478 * @see javax.comm.SerialPort for flow control definitions 479 * @param flowControl Flow control settings setting 480 */ 481 public void setFlowControl(int flowControl) { 482 this.flowControl = flowControl; 483 } 484 485 /*** 486 * Get flow control 487 * @return Current flow control setting. 488 */ 489 public int getFlowControl() { 490 return this.flowControl; 491 } 492 493 /*** 494 * Convert array of bytes to space separated hex string for debug display 495 * @param chars Array of chars 496 * @return String for display 497 */ 498 public static String displayCharArrayAsHexString(char[] chars) { 499 StringBuffer buf = new StringBuffer(); 500 501 if (chars != null) { 502 for (int i = 0; i < chars.length; i++) { 503 504 if (i != 0) { 505 buf.append(" "); 506 } 507 508 buf.append("char["); 509 buf.append(i); 510 buf.append("]=0x"); 511 buf.append(Integer.toString(chars[i], 16)); 512 } 513 } else { 514 buf.append("chars is null"); 515 } 516 517 return buf.toString(); 518 } 519 520 /*** 521 * Set debug flag 522 * @param debug Set to true to list cmds sent, responses received 523 */ 524 public void setDebug(boolean debug) { 525 this.debug = debug; 526 } 527 528 /*** 529 * Check debug flag 530 * return true if set 531 * @return boolean 532 */ 533 public boolean isDebug() { 534 return this.debug; 535 } 536 537 /*** 538 * Get serial ports 539 * @return String array of ports on workstation (may return null) 540 */ 541 public static String[] getAvailablePorts() { 542 Enumeration enum = CommPortIdentifier.getPortIdentifiers(); 543 String[] retStr = null; 544 ArrayList list = new ArrayList(); 545 546 while (enum.hasMoreElements()) { 547 CommPortIdentifier comId = (CommPortIdentifier) enum.nextElement(); 548 549 if (comId.getPortType() == CommPortIdentifier.PORT_SERIAL) { 550 list.add(comId.getName()); 551 } 552 } 553 554 555 Object[] ports = list.toArray(); 556 557 if (ports != null) { 558 retStr = new String[ports.length]; 559 560 for (int i = 0; i < ports.length; i++) { 561 retStr[i] = (String) ports[i]; 562 } 563 } 564 565 return retStr; 566 } 567 568 /*** 569 * Class to synchronize values received from serial connection 570 */ 571 class MessageQueue { 572 /*** Queue containing responses */ 573 private LinkedList queue = new LinkedList(); 574 575 /*** 576 * Add message to queue 577 * @param txt The message to add 578 */ 579 public void addMessage(String txt) { 580 581 synchronized (queue) { 582 queue.addLast(txt); 583 } 584 585 } 586 587 /*** 588 * Add characters to queue 589 * @param chars Array of char to add 590 */ 591 public void addChars(char[] chars) { 592 synchronized (queue) { 593 queue.addLast(chars); 594 } 595 } 596 597 /*** 598 * Get message from queue as a char array 599 * @return char[] 600 */ 601 public char[] getChars() { 602 boolean empty = true; 603 char[] chars = null; 604 605 synchronized (queue) { 606 empty = queue.isEmpty(); 607 } 608 609 if (!empty) { 610 611 synchronized (queue) { 612 chars = (char[]) queue.removeFirst(); 613 } 614 } 615 616 return chars; 617 } 618 619 /*** 620 * Size of the queue 621 * @return Number of messages in queue 622 */ 623 public int size() { 624 synchronized (queue) { 625 return queue.size(); 626 } 627 } 628 629 /*** 630 * Check if queue is empty 631 * @return True if empty, false otherwise 632 */ 633 public boolean isEmpty() { 634 synchronized (queue) { 635 return queue.isEmpty(); 636 } 637 } 638 639 /*** 640 * Get String message from queue 641 * @return The message as a string 642 */ 643 public String getMessage() { 644 boolean empty = true; 645 String msg = ""; 646 647 648 synchronized (queue) { 649 empty = queue.isEmpty(); 650 } 651 652 if (!empty) { 653 synchronized (queue) { 654 char[] chars = (char[]) queue.removeFirst(); 655 if (chars != null) { 656 msg = new String(chars); 657 } 658 } 659 } 660 661 662 return msg; 663 } 664 665 } 666 667 668 }

This page was automatically generated by Maven