The program in Example 12-10 is an outgrowth of the Plotter class from Recipe 9.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, several companies still make pen plotters. See Figure 12-4 for a photograph of the plotter in action. Figure 12-4. Penman plotter in actionExample 12-10. Penman.javaimport 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. * */ public class Penman extends Plotter { private final String OK_PROMPT = "\r\n!"; private final int MAX_REPLY_BYTES = 50; // paranoid upper bound 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 + "\r"); 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 // (XXX Should re-use CommPortOpen here). 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.FLOWCONTROL_RTSCTS_OUT| SerialPort.FLOWCONTROL_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)); } } See AlsoThe online source includes a program called JModem that implements remote connections (like tip or cu on Unix, or HyperTerminal on Windows). It is usable but too long to include in this book. As mentioned, a USB standard for Java is in progress; check on http://www.jcp.org/jsr/detail/80.jsp to see if it has been released by the time you read this. The JSR reference implementation can be downloaded from http://sourceforge.net/projects/javax-usb/. 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 one of various third-party APIs such as jSyncManager by Brad Barclay, now available from http://www.jsyncmanager.org/. Consult your favorite search engine to find others. There is also an XML-based synchronization interface for mobile devices, called SyncML. Information about SyncML can be found at http://www.openmobilealliance.org/syncml/. |