This program in Example 11-10 is
an outgrowth of the
Plotter
class from Section 8.12.
It connects to a Penman plotter. These
serial-port plotters were made in the United Kingdom in the 1980s, so
it is unlikely that you will meet one. However, there are several
companies that still make pen plotters. See Figure 11-4 for a photograph of the plotter in action.
Example 11-10. Penman.java
import java.io.*; import javax.comm.*; import java.util.*; /** * A Plotter subclass for drawing on a Penman plotter. * These were made in the UK and sold into North American markets. * It is a little "turtle" style robot plotter that communicates * over a serial port. For this, we use the "Java Communications" API. * Java Communications is a "standard extension" and must be downloaded * and installed separately from the JDK before you can even compile this * program. * */ public class Penman extends Plotter { private final String OK_PROMPT = " !"; private final int MAX_REPLY_BYTES = 50; // paranoid upper bound private byte b, reply[] = new byte[22]; private SerialPort tty; private DataInputStream is; private DataOutputStream os; /** Construct a Penman plotter object */ public Penman( ) throws NoSuchPortException,PortInUseException, IOException,UnsupportedCommOperationException { super( ); init_comm("COM2"); // setup serial commx init_plotter( ); // set plotter to good state } private void init_plotter( ) { send("I"); expect('!'), // eat VERSION etc., up to ! send("I"); expect('!'), // wait for it! send("H"); // find home position expect('!'), // wait for it! send("A"); // Set to use absolute coordinates expect('!'), curx = cury = 0; penUp( ); } // // PUBLIC DRAWING ROUTINES // public void setFont(String fName, int fSize) { // Font name is ignored for now... // Penman's size is in mm, fsize in points (inch/72). int size = (int)(fSize*25.4f/72); send("S"+size + ","); expect(OK_PROMPT); System.err.println("Font set request: " + fName + "/" + fSize); } public void drawString(String mesg) { send("L" + mesg + " "); expect(OK_PROMPT); } /** Move to a relative location */ public void rmoveTo(int incrx, int incry){ moveTo(curx + incrx, cury + incry); } /** move to absolute location */ public void moveTo(int absx, int absy) { System.err.println("moveTo ["+absx+","+absy+"]"); curx = absx; cury = absy; send("M" + curx + "," + cury + ","); expect(OK_PROMPT); } private void setPenState(boolean up) { penIsUp = up; System.err.println("Pen Up is ["+penIsUp+"]"); } public void penUp( ) { setPenState(true); send("U"); expect(OK_PROMPT); } public void penDown( ) { setPenState(false); send("D"); expect(OK_PROMPT); } public void penColor(int c) { penColor = (c%3)+1; // only has 3 pens, 4->1 System.err.println("PenColor is ["+penColor+"]"); send("P" + c + ","); expect(OK_PROMPT); } // // PRIVATE COMMUNICATION ROUTINES // private void init_comm(String portName) throws IOException, UnsupportedCommOperationException { // get list of ports available on this particular computer. // Enumeration pList = CommPortIdentifier.getPortIdentifiers( ); // Print the list. A GUI program would put these in a chooser! // while (pList.hasMoreElements( )) { // CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement( ); // System.err.println("Port " + cpi.getName( )); // } // Open a port. CommPortIdentifier port = CommPortIdentifier.getPortIdentifier(portName); // This form of openPort takes an Application Name and a timeout. tty = (SerialPort) port.openPort("Penman Driver", 1000); // set up the serial port tty.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); tty.setFlowcontrolMode(SerialPort.FLOWCTRL_RTSCTS_OUT| SerialPort.FLOWCTRL_RTSCTS_OUT); // Get the input and output streams is = new DataInputStream(tty.getInputStream( )); os = new DataOutputStream(tty.getOutputStream( )); } /** Send a command to the plotter. Although the argument is a String, * we send each char as a *byte*, so avoid 16-bit characters! * Not that it matters: the Penman only knows about 8-bit chars. */ private void send(String s) { System.err.println("sending " + s + "..."); try { for (int i=0; i<s.length( ); i++) os.writeByte(s.charAt(i)); } catch(IOException e) { e.printStackTrace( ); } } /** Expect a given CHAR for a result */ private void expect(char s) { byte b; try { for (int i=0; i<MAX_REPLY_BYTES; i++){ if ((b = is.readByte( )) == s) { return; } System.err.print((char)b); } } catch (IOException e) { System.err.println("Penman:expect(char "+s+"): Read failed"); System.exit(1); } System.err.println("ARGHH!"); } /** Expect a given String for a result */ private void expect(String s) { byte ans[] = new byte[s.length( )]; System.err.println("expect " + s + " ..."); try { is.read(ans); } catch (IOException e) { System.err.println("Penman:expect(String "+s+"): Read failed"); System.exit(1); }; for (int i=0; i<s.length( ) && i<ans.length; i++) if (ans[i] != s.charAt(i)) { System.err.println("MISMATCH"); break; } System.err.println("GOT: " + new String(ans)); } }
In the online source there is a program called JModem, which implements remote connections (like tip or cu on Unix, or HyperTerminal on MS-Windows). It is usable, but too long to include in this book.
There are other specialized APIs for dealing with particular devices. For communicating with Palm Computing Platform devices, you can either use the Palm SDK for Java from Palm Computing, or the third-party API jSyncManager by Brad Barclay, which can be obtained from http://web.idirect.com/~warp/.
18.226.34.197