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