The open( ) method of the CommPortIdentifier class returns a CommPort object. The CommPort class has methods for getting input and output streams from a port and for closing the port. There are also a number of driver-dependent methods for adjusting the properties of the port.
There are five basic steps to communicating with a port:
Open the port using the open( ) method of CommPortIdentifier. If the port is available, this returns a CommPort object. Otherwise, it throws a PortInUseException.
Get the ports output stream using the getOutputStream( ) method of CommPort.
Get the ports input stream using the getInputStream( ) method of CommPort.
Read and write data onto those streams as desired.
Close the port using the close( ) method of CommPort.
Steps 2 through 4 are new. However, they e not particularly complex. Once the connection has been established, you simply use the normal methods of any input or output stream to read and write data. The getInputStream( ) and getOutputStream( ) methods of CommPort are similar to the methods of the same name in the java.net.URL class. The primary difference is that with ports, you e completely responsible for understanding and handling the data thats sent to you. There are no content or protocol handlers that perform any manipulation of the data. If the device attached to the port requires a complicated protocolfor example, a fax modemyoull have to handle the protocol manually.
public abstract InputStream getInputStream( ) throws IOException public abstract OutputStream getOutputStream( ) throws IOException
Some ports are unidirectional. In other words, the port hardware only supports writing or reading, not both. For instance, early PC parallel ports allowed the computer to send data to the printer but could only send a small number of precisely defined signals back to the computer. This was fine for a printer, but it meant that the parallel port wasn useful for a device like a CD-ROM or a Zip drive. If the port youve opened doesn allow writing, getOutputStream( ) returns null. If the port doesn allow reading, getInputStream( ) returns null.
Example 22-5 is a simple character-mode program that allows you to type back and forth with a port. If a modem is attached to the port, you can use it as an extremely rudimentary terminal emulator. Two separate threads handle input and output so that input doesn get blocked waiting for output and vice versa.
import javax.comm.*; import java.util.*; import java.io.*; public class PortTyper { public static void main(String[] args) { if (args.length < 1) { System.out.println("Usage: java PortTyper portName"); return; } try { CommPortIdentifier com = CommPortIdentifier.getPortIdentifier(args[0]); CommPort thePort = com.open("PortOpener", 10); CopyThread input = new CopyThread(System.in, thePort.getOutputStream( )); CopyThread output = new CopyThread(thePort.getInputStream( ), System.out); input.start( ); output.start( ); } catch (Exception ex) {System.out.println(ex);} } } class CopyThread extends Thread { private InputStream theInput; private OutputStream theOutput; CopyThread(InputStream in) { this(in, System.out); } CopyThread(OutputStream out) { this(System.in, out); } CopyThread(InputStream in, OutputStream out) { theInput = in; theOutput = out; } public void run( ) { try { byte[] buffer = new byte[256]; while (true) { int bytesRead = theInput.read(buffer); if (bytesRead == -1) break; theOutput.write(buffer, 0, bytesRead); } } catch (IOException ex) {System.err.println(ex);} } } |
Heres a sample session where I used this program to connect to my ISP. After I logged out, the incoming line rang three times, which you also see:
D:JAVA22java PortTyper COM2 at&f at&f OK atdt 321-1444 atdt 321-1444 CONNECT 9600/ARQ Welcome to Cloud 9 Internet! If you e already a user, please login below. To sign up for an account, type ew, with no password. If you have trouble logging in, please call (914)696-4000. login: elharo elharo Password: ********** Password: ********** Last login: Thu May 28 18:26:14 from 168.100.253.71 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 2.2.6-RELEASE (EARL-GREY) #0: Tue May 19 10:39:36 EDT 1998 You have new mail. > logout logo Connection closed. NO CARRIER RING RING RING
This program would have been state of the art in 1978. These days, its rather crude, and youd have to do a lot of work to develop it further. For one thing, local echo mode should be turned off in the modem so that you don see duplicates of everything you type. (Even my password originally appeared on the screen in clear text. I replaced it with asterisks manually.) And no effort at all is made to perform terminal emulation of any sort. Furthermore, theres no way to exit the program and close the port. Terminating it with a Ctrl-C forces abnormal execution that fails to release control of the port. Nonetheless, its amazing just how quick and easy it is to write a program that communicates with a simple serial port device. Communicating with a basic daisy-wheel printer would be no harder.
The CommPort class has a number of driver-dependent methods for adjusting the properties of the port. These properties are mostly generic characteristics such as buffer size that can be implemented in software. More specific properties of a particular type of port, like the baud rate of a serial port or the mode of the parallel port, must be set using a more specific subclass, like SerialPort or ParallelPort.
The five generic properties are receive threshold, timeout value, receive framing byte, input buffer size, and output buffer size:
Together, the receive threshold and the receive timeout determine exactly how long the input stream will wait for incoming data. For instance, if the receive threshold is set to 5, read( ) won return until at least 5 bytes are available. If the receive timeout is set to 10 milliseconds, read( ) will wait 10 milliseconds before returning. However, if data becomes available before 10 milliseconds are up, read( ) returns immediately. For example, if the receive threshold is set to 5 bytes and the receive timeout is set to 10 milliseconds, read( ) will wait until either 10 milliseconds pass or 5 bytes are available before returning. Finally, if receive framing is enabled, all reads return immediately, regardless of the other values. However, you need to check each read and discard any dummy bytes in the input stream.
Each of these properties has four methods: one enables the property, one disables it, one checks whether the property is enabled, and one returns the current value. For instance, the receive threshold is adjusted by these four methods:
public abstract void enableReceiveThreshold(int size) throws UnsupportedCommOperationException public abstract void disableReceiveThreshold( ) public abstract boolean isReceiveThresholdEnabled( ) public abstract int getReceiveThreshold( )
The other three properties follow the same naming conventions. These four methods adjust the receive timeout:
public abstract void enableReceiveTimeout(int ms) throws UnsupportedCommOperationException public abstract void disableReceiveTimeout( ) public abstract boolean isReceiveTimeoutEnabled( ) public abstract int getReceiveTimeout( )
These four methods adjust the receive framing property:
public abstract void enableReceiveFraming(int dummyByte) throws UnsupportedCommOperationException public abstract void disableReceiveFraming( ) public abstract boolean isReceiveFramingEnabled( ) public abstract int getReceiveFramingByte( )
These four methods adjust the input and output buffer sizes:
public abstract void setInputBufferSize(int size) public abstract int getInputBufferSize( ) public abstract void setOutputBufferSize(int size) public abstract int getOutputBufferSize( )
All drivers must support input and output buffers, so there are no isInputBufferEnabled( ) or disableOutputBuffer( ) methods. However, other than the input and output buffer sizes, drivers are not required to support these properties. If a driver does not support the given property, attempting to enable it throws an UnsupportedCommOperationException. You can determine whether or not a driver supports a property by trying to enable it and seeing whether an exception is thrown. Example 22-6 uses this scheme to test the properties for the ports of the host system.
import javax.comm.*; import java.util.*; public class PortTester { public static void main(String[] args) { Enumeration thePorts = CommPortIdentifier.getPortIdentifiers( ); while (thePorts.hasMoreElements( )) { CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement( ); System.out.print(com.getName( )); switch(com.getPortType( )) { case CommPortIdentifier.PORT_SERIAL: System.out.println(", a serial port: "); break; case CommPortIdentifier.PORT_PARALLEL: System.out.println(", a parallel port: "); break; default: System.out.println(" , a port of unknown type: "); break; } try { CommPort thePort = com.open("Port Tester", 20); testProperties(thePort); thePort.close( ); } catch (PortInUseException ex) { System.out.println("Port in use, can test properties"); } System.out.println( ); } } public static void testProperties(CommPort thePort) { try { thePort.enableReceiveThreshold(10); System.out.println("Receive threshold supported"); } catch (UnsupportedCommOperationException ex) { System.out.println("Receive threshold not supported"); } try { thePort.enableReceiveTimeout(10); System.out.println("Receive timeout not supported"); } catch (UnsupportedCommOperationException e) { System.out.println("Receive timeout not supported"); } try { thePort.enableReceiveFraming(10); System.out.println("Receive framing supported"); } catch (UnsupportedCommOperationException e) { System.out.println("Receive framing not supported"); } } } |
Heres the results for both serial and parallel ports from a Windows NT box running the Comm API 2.0:
D:JAVA22>java PortTester COM1, a serial port: Receive threshold supported Receive timeout supported Receive framing supported COM2, a serial port: Port in use, can test properties LPT1, a parallel port: Receive threshold supported Receive timeout supported Receive framing supported LPT2, a parallel port: Port in use, can test properties